package uploads import ( "context" "errors" "sort" "github.com/google/uuid" "pipu/api/internal/acoustid" ) const maxAudioFiles = 50 func chooseAudioMatch(id uuid.UUID, matches []acoustid.Match) AudioRecognition { // Multiple AcoustIDs can point to the same recording. Compare distinct recordings only. best := map[string]float64{} for _, m := range matches { if parsed, err := uuid.Parse(m.RecordingID); err == nil && parsed != uuid.Nil && m.Score > best[parsed.String()] && m.Score <= 1 { best[parsed.String()] = m.Score } } unique := []acoustid.Match{} for id, score := range best { unique = append(unique, acoustid.Match{RecordingID: id, Score: score}) } sort.Slice(unique, func(i, j int) bool { return unique[i].Score > unique[j].Score }) r := AudioRecognition{FileID: id, State: "not_found"} if len(unique) == 0 { return r } r.Score = unique[0].Score if unique[0].Score < .9 || len(unique) > 1 && unique[0].Score-unique[1].Score < .05 { r.State = "ambiguous" return r } r.State, r.RecordingID = "matched", unique[0].RecordingID return r } // identifyAudio runs only after an explicit reviewer request. It never modifies file tags. func (s *Service) identifyAudio(ctx context.Context, files []File) ([]AudioRecognition, map[uuid.UUID]AudioRecognition, []string, error) { results := []AudioRecognition{} byFile := map[uuid.UUID]AudioRecognition{} ids := []string{} if s.identifier == nil || s.encodedFingerprint == nil { return results, byFile, ids, errors.New("acoustid: not configured") } for _, f := range releaseFiles(files) { if f.Status != StatusPendingReview && f.Status != StatusImportFailed { continue } if len(results) >= maxAudioFiles { return results, byFile, ids, errors.New("acoustid: batch too large") } r := AudioRecognition{FileID: f.ID, State: "unavailable"} if f.DurationMs != nil && *f.DurationMs > 0 && f.StagingPath != "" { fingerprint, err := s.encodedFingerprint(ctx, s.stagingAbs(f.StagingPath)) if err == nil { matches, err := s.identifier.Lookup(ctx, fingerprint, (*f.DurationMs+500)/1000) if err != nil { return results, byFile, ids, err } r = chooseAudioMatch(f.ID, matches) } } if err := ctx.Err(); err != nil { return results, byFile, ids, err } results = append(results, r) byFile[f.ID] = r if r.State == "matched" { ids = append(ids, r.RecordingID) } } return results, byFile, ids, nil }