Refactor MonitorAlbum into focused methods

This commit is contained in:
Alexander
2026-05-07 23:28:35 +02:00
parent 8ad2734964
commit 84a6fe8ec7
+98 -70
View File
@@ -84,42 +84,81 @@ func (s *MusicAgregatorService) Close() {
} }
func (service *MusicAgregatorService) MonitorAlbum(ctx context.Context, req *pb.MonitorAlbumRequest) (*pb.MonitorAlbumResponse, error) { func (service *MusicAgregatorService) MonitorAlbum(ctx context.Context, req *pb.MonitorAlbumRequest) (*pb.MonitorAlbumResponse, error) {
resp, err := service.metadataClient.GetAlbum(ctx, &metadataPb.GetAlbumRequest{ album, err := service.fetchAlbumMetadata(ctx, req.GetAlbumId())
Identifier: &metadataPb.GetAlbumRequest_Id{Id: req.GetAlbumId()},
})
if err != nil { if err != nil {
log.Error().Err(err).Str("album_id", req.GetAlbumId()).Msg("metadata GetAlbum failed")
return nil, err return nil, err
} }
searchResult, err := service.searchIndexer(album, req.GetIndexerOptions().GetTracker())
if err != nil {
return nil, err
}
parsed := service.parseSearchResults(searchResult, album)
filtered := filterByQuality(parsed, req.GetQuality())
if len(filtered) == 0 {
log.Warn().Str("album", album.GetTitle()).Str("quality", req.GetQuality().String()).Msg("no releases match quality filter")
return &pb.MonitorAlbumResponse{}, nil
}
best := selectBestRelease(filtered)
if err := service.addToTorrentClient(best); err != nil {
return nil, err
}
return &pb.MonitorAlbumResponse{
Release: buildMonitoredRelease(best),
}, nil
}
func (service *MusicAgregatorService) fetchAlbumMetadata(ctx context.Context, albumID string) (*metadataPb.Album, error) {
resp, err := service.metadataClient.GetAlbum(ctx, &metadataPb.GetAlbumRequest{
Identifier: &metadataPb.GetAlbumRequest_Id{Id: albumID},
})
if err != nil {
log.Error().Err(err).Str("album_id", albumID).Msg("metadata GetAlbum failed")
return nil, err
}
album := resp.GetAlbum() album := resp.GetAlbum()
artistName := "" artistName := ""
if len(album.GetArtists()) > 0 { if len(album.GetArtists()) > 0 {
artistName = album.GetArtists()[0].GetArtist().GetName() artistName = album.GetArtists()[0].GetArtist().GetName()
} }
log.Debug(). log.Debug().Str("album_id", albumID).Str("title", album.GetTitle()).Str("artist", artistName).Msg("album metadata fetched")
Str("album_id", req.GetAlbumId()).
Str("title", album.GetTitle()). return album, nil
Str("artist", artistName). }
Msg("album found, monitoring")
func (service *MusicAgregatorService) searchIndexer(album *metadataPb.Album, tracker string) (*indexer.SearchResponse, error) {
artistName := ""
if len(album.GetArtists()) > 0 {
artistName = album.GetArtists()[0].GetArtist().GetName()
}
query := album.GetTitle() query := album.GetTitle()
if artistName != "" { if artistName != "" {
query = artistName + " " + query query = artistName + " " + query
} }
trackerName := req.GetIndexerOptions().GetTracker() if tracker == "" {
if trackerName == "" { tracker = "all"
trackerName = "all"
} }
searchResult, err := service.indexer.Search(query, -1, trackerName) result, err := service.indexer.Search(query, -1, tracker)
if err != nil { if err != nil {
log.Error().Err(err).Str("query", query).Msg("indexer search album failed") log.Error().Err(err).Str("query", query).Msg("indexer search failed")
return nil, err return nil, err
} }
log.Debug().Int("results", len(searchResult.Items)).Str("query", query).Msg("indexer search completed")
log.Debug().Int("results", len(result.Items)).Str("query", query).Msg("indexer search completed")
return result, nil
}
func (service *MusicAgregatorService) parseSearchResults(searchResult *indexer.SearchResponse, album *metadataPb.Album) []parsedItem {
parser := torrentParser.NewGenericParser() parser := torrentParser.NewGenericParser()
var parsed []parsedItem var parsed []parsedItem
@@ -134,27 +173,7 @@ func (service *MusicAgregatorService) MonitorAlbum(ctx context.Context, req *pb.
continue continue
} }
var r *release.Release r, torrentData := service.resolveRelease(parser, item, album)
var torrentData []byte
if strings.HasPrefix(item.DownloadLink, "magnet:") {
log.Trace().Str("title", item.Title).Int("reported_seeders", item.Seeders).Msg("resolving magnet")
torrentData, err = service.magnetResolver.Resolve(item.DownloadLink)
if err != nil {
log.Warn().Err(err).Str("title", item.Title).Int("reported_seeders", item.Seeders).Msg("magnet resolve failed, falling back to title parse")
r = parser.Parse(item.Title)
} else {
r = parser.ParseTorrent(torrentData, album)
}
} else {
torrentData, err = downloadTorrentData(item.DownloadLink)
if err != nil {
log.Warn().Err(err).Str("title", item.Title).Msg("failed to download torrent, falling back to title parse")
r = parser.Parse(item.Title)
} else {
r = parser.ParseTorrent(torrentData, album)
}
}
log.Debug(). log.Debug().
Str("title", item.Title). Str("title", item.Title).
@@ -169,28 +188,47 @@ func (service *MusicAgregatorService) MonitorAlbum(ctx context.Context, req *pb.
} }
log.Debug().Int("total", len(searchResult.Items)).Int("parsed", len(parsed)).Msg("parsing complete") log.Debug().Int("total", len(searchResult.Items)).Int("parsed", len(parsed)).Msg("parsing complete")
return parsed
}
qualityType := req.GetQuality() func (service *MusicAgregatorService) resolveRelease(parser *torrentParser.GenericParser, item *indexer.SearchItemResult, album *metadataPb.Album) (*release.Release, []byte) {
if strings.HasPrefix(item.DownloadLink, "magnet:") {
log.Trace().Str("title", item.Title).Int("reported_seeders", item.Seeders).Msg("resolving magnet")
torrentData, err := service.magnetResolver.Resolve(item.DownloadLink)
if err != nil {
log.Warn().Err(err).Str("title", item.Title).Int("reported_seeders", item.Seeders).Msg("magnet resolve failed, falling back to title parse")
return parser.Parse(item.Title), nil
}
return parser.ParseTorrent(torrentData, album), torrentData
}
torrentData, err := downloadTorrentData(item.DownloadLink)
if err != nil {
log.Warn().Err(err).Str("title", item.Title).Msg("failed to download torrent, falling back to title parse")
return parser.Parse(item.Title), nil
}
return parser.ParseTorrent(torrentData, album), torrentData
}
func filterByQuality(items []parsedItem, quality pb.QualityType) []parsedItem {
var filtered []parsedItem var filtered []parsedItem
for _, p := range parsed { for _, p := range items {
match := qualityType == pb.QualityType_QUALITY_UNSPECIFIED || match := quality == pb.QualityType_QUALITY_UNSPECIFIED ||
(qualityType == pb.QualityType_QUALITY_LOSSLESS && p.rel.Format.IsLossless()) || (quality == pb.QualityType_QUALITY_LOSSLESS && p.rel.Format.IsLossless()) ||
(qualityType == pb.QualityType_QUALITY_LOSSY && !p.rel.Format.IsLossless()) (quality == pb.QualityType_QUALITY_LOSSY && !p.rel.Format.IsLossless())
if !match { if !match {
log.Debug().Str("title", p.item.Title).Str("format", p.rel.Format.String()).Str("wanted", qualityType.String()).Msg("filtered out by quality") log.Debug().Str("title", p.item.Title).Str("format", p.rel.Format.String()).Str("wanted", quality.String()).Msg("filtered out by quality")
continue continue
} }
filtered = append(filtered, p) filtered = append(filtered, p)
} }
return filtered
}
if len(filtered) == 0 { func selectBestRelease(items []parsedItem) parsedItem {
log.Warn().Str("query", query).Str("quality", qualityType.String()).Msg("no releases match quality filter") best := items[0]
return &pb.MonitorAlbumResponse{}, nil for _, p := range items[1:] {
}
best := filtered[0]
for _, p := range filtered[1:] {
if p.item.Seeders > best.item.Seeders { if p.item.Seeders > best.item.Seeders {
best = p best = p
} }
@@ -202,51 +240,41 @@ func (service *MusicAgregatorService) MonitorAlbum(ctx context.Context, req *pb.
Int("seeders", best.item.Seeders). Int("seeders", best.item.Seeders).
Str("tracker", best.item.Tracker). Str("tracker", best.item.Tracker).
Str("hash", best.rel.InfoHash). Str("hash", best.rel.InfoHash).
Msg("best release selected, adding to torrent client") Msg("best release selected")
return best
}
func (service *MusicAgregatorService) addToTorrentClient(best parsedItem) error {
if best.rel.InfoHash != "" { if best.rel.InfoHash != "" {
existing, err := service.torrentClient.Find(torrent.FindOptions{Hash: best.rel.InfoHash}) existing, err := service.torrentClient.Find(torrent.FindOptions{Hash: best.rel.InfoHash})
if err == nil && len(existing) > 0 { if err == nil && len(existing) > 0 {
log.Info(). log.Info().Str("hash", best.rel.InfoHash).Str("state", existing[0].State).Msg("torrent already exists in client")
Str("hash", best.rel.InfoHash). return nil
Str("state", existing[0].State).
Str("artist", best.rel.Artist).
Str("album", best.rel.Album).
Str("format", best.rel.Format.String()).
Int("tracks", best.rel.TrackCount).
Msg("torrent already exists in client")
resp := buildMonitoredRelease(best)
log.Trace().Interface("response", resp).Msg("returning existing torrent response")
return &pb.MonitorAlbumResponse{
Release: resp,
}, nil
} }
} }
if strings.HasPrefix(best.item.DownloadLink, "magnet:") { if strings.HasPrefix(best.item.DownloadLink, "magnet:") {
if err := service.torrentClient.AddMagnet(best.item.DownloadLink); err != nil { if err := service.torrentClient.AddMagnet(best.item.DownloadLink); err != nil {
log.Error().Err(err).Str("title", best.item.Title).Msg("failed to add magnet to client") log.Error().Err(err).Str("title", best.item.Title).Msg("failed to add magnet to client")
return nil, err return err
} }
} else { } else {
if len(best.torrentData) == 0 { if len(best.torrentData) == 0 {
log.Error().Str("title", best.item.Title).Msg("no torrent data available") log.Error().Str("title", best.item.Title).Msg("no torrent data available")
return nil, fmt.Errorf("no torrent data available for best release") return fmt.Errorf("no torrent data available for best release")
} }
if err := service.torrentClient.AddTorrent(torrent.TorrentFile{ if err := service.torrentClient.AddTorrent(torrent.TorrentFile{
Filename: best.rel.Album + ".torrent", Filename: best.rel.Album + ".torrent",
Data: best.torrentData, Data: best.torrentData,
}); err != nil { }); err != nil {
log.Error().Err(err).Str("title", best.item.Title).Msg("failed to add torrent to client") log.Error().Err(err).Str("title", best.item.Title).Msg("failed to add torrent to client")
return nil, err return err
} }
} }
log.Info().Str("title", best.item.Title).Str("hash", best.rel.InfoHash).Msg("torrent added to client") log.Info().Str("title", best.item.Title).Str("hash", best.rel.InfoHash).Msg("torrent added to client")
return nil
return &pb.MonitorAlbumResponse{
Release: buildMonitoredRelease(best),
}, nil
} }
func buildMonitoredRelease(p parsedItem) *pb.MonitoredRelease { func buildMonitoredRelease(p parsedItem) *pb.MonitoredRelease {