Files
music-agregator/internal/services/album.go
T

201 lines
4.4 KiB
Go

package services
import (
"context"
"sort"
"strings"
"github.com/fujin/music-agregator/internal/database"
"github.com/fujin/music-agregator/internal/indexer"
"github.com/google/uuid"
)
type RankedSearchResult struct {
indexer.SearchResult
Quality string `json:"quality"`
Score float64 `json:"score"`
}
type AlbumSearchResult struct {
AlbumID string `json:"album_id"`
AlbumTitle string `json:"album_title"`
ArtistName string `json:"artist_name"`
Results []RankedSearchResult `json:"results"`
TotalResults int `json:"total_results"`
}
func SearchAlbum(
ctx context.Context,
albumID uuid.UUID,
db *database.DB,
indexerService *IndexerService,
) (*AlbumSearchResult, error) {
album, err := db.GetAlbumDetailByID(ctx, albumID)
if err != nil {
return nil, err
}
var year *uint32
if album.ReleaseDate != nil {
y := uint32(album.ReleaseDate.Year())
year = &y
}
criteria := &indexer.MusicSearchCriteria{
Artist: album.ArtistName,
Album: &album.Title,
Year: year,
Limit: 100,
Offset: 0,
}
results, err := indexerService.Search(ctx, criteria, nil)
if err != nil {
return nil, err
}
var rankedResults []RankedSearchResult
for _, r := range results {
blocked, _ := db.IsBlocklisted(ctx, r.Title, r.Infohash)
if blocked {
continue
}
quality := detectQuality(r.Title)
score := calculateScore(quality, r.Seeders)
rankedResults = append(rankedResults, RankedSearchResult{
SearchResult: r,
Quality: quality,
Score: score,
})
}
sort.Slice(rankedResults, func(i, j int) bool {
return rankedResults[i].Score > rankedResults[j].Score
})
return &AlbumSearchResult{
AlbumID: albumID.String(),
AlbumTitle: album.Title,
ArtistName: album.ArtistName,
Results: rankedResults,
TotalResults: len(rankedResults),
}, nil
}
func detectQuality(title string) string {
titleLower := strings.ToLower(title)
if strings.Contains(titleLower, "flac") || strings.Contains(titleLower, "lossless") {
return "FLAC"
}
if strings.Contains(titleLower, "24bit") || strings.Contains(titleLower, "24-bit") || strings.Contains(titleLower, "hi-res") {
return "FLAC-24bit"
}
if strings.Contains(titleLower, "320") || strings.Contains(titleLower, "mp3-320") {
return "MP3-320"
}
if strings.Contains(titleLower, "v0") || strings.Contains(titleLower, "vbr") {
return "MP3-VBR"
}
if strings.Contains(titleLower, "mp3") {
return "MP3"
}
if strings.Contains(titleLower, "aac") {
return "AAC"
}
if strings.Contains(titleLower, "ogg") {
return "OGG"
}
return "Unknown"
}
func calculateScore(quality string, seeders *int) float64 {
var score float64
switch quality {
case "FLAC-24bit":
score = 1000
case "FLAC":
score = 900
case "MP3-320":
score = 700
case "MP3-VBR":
score = 600
case "MP3":
score = 500
case "AAC":
score = 400
case "OGG":
score = 350
default:
score = 100
}
if seeders != nil && *seeders > 0 {
score += float64(*seeders) * 0.1
if *seeders > 100 {
score += 50
}
}
return score
}
type ArtistSearchResult struct {
ArtistID string `json:"artist_id"`
ArtistName string `json:"artist_name"`
AlbumsSearched int `json:"albums_searched"`
Results []AlbumBriefResult `json:"results"`
}
type AlbumBriefResult struct {
AlbumID string `json:"album_id"`
AlbumTitle string `json:"album_title"`
ResultsCount int `json:"results_count"`
}
func SearchArtistAlbums(
ctx context.Context,
foreignArtistID string,
db *database.DB,
indexerService *IndexerService,
) (*ArtistSearchResult, error) {
artist, err := db.GetArtistMetadataByForeignID(ctx, foreignArtistID)
if err != nil {
return nil, err
}
albums, err := db.GetMonitoredAlbumsByArtist(ctx, artist.ID)
if err != nil {
return nil, err
}
var results []AlbumBriefResult
for _, album := range albums {
searchResult, err := SearchAlbum(ctx, album.ID, db, indexerService)
if err != nil {
results = append(results, AlbumBriefResult{
AlbumID: album.ID.String(),
AlbumTitle: album.Title,
ResultsCount: 0,
})
continue
}
results = append(results, AlbumBriefResult{
AlbumID: album.ID.String(),
AlbumTitle: album.Title,
ResultsCount: searchResult.TotalResults,
})
}
return &ArtistSearchResult{
ArtistID: foreignArtistID,
ArtistName: artist.Name,
AlbumsSearched: len(albums),
Results: results,
}, nil
}