package media import ( "encoding/json" "errors" "fmt" "io" u "net/url" "os/exec" "strings" "codeberg.org/danjones000/strip-beats/config" "codeberg.org/danjones000/strip-beats/media/brainz" h "codeberg.org/danjones000/strip-beats/utils/http" "github.com/google/uuid" ) type FPrint struct { Duration float64 Fingerprint string } func Fingerprint(path string) (FPrint, error) { pr := FPrint{} _, err := exec.LookPath("fpcalc") if err != nil { return pr, errors.Join(errors.New("Unable to find fpcalc in PATH"), err) } cmd := exec.Command("fpcalc", "-json", path) out, err := cmd.Output() if err != nil { return pr, errors.Join(errors.New(fmt.Sprintf("Failed to run %s", strings.Join(cmd.Args, " "))), err) } err = json.Unmarshal(out, &pr) if err != nil { return pr, errors.Join(errors.New("Couldn't parse output from fpcalc"), err) } return pr, nil } type IdResults struct { Status string Results []IdResult Error IdError } type IdResult struct { Id uuid.UUID Score float64 Recordings []brainz.Recording } type IdError struct { Code int Message string } func LookupFingerprint(print FPrint) (IdResults, error) { res := IdResults{} key := config.GetConfig().AcousticIdKey if key == "" { return res, errors.New("Missing acoustic_id_key from config") } url := "https://api.acoustid.org/v2/lookup" form := u.Values{ "format": {"json"}, "client": {key}, "duration": {fmt.Sprintf("%.0f", print.Duration)}, "fingerprint": {print.Fingerprint}, "meta": {"recordingids"}} resp, err := h.PostForm(url, form) if err != nil { return res, err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return res, err } json.Unmarshal(body, &res) if res.Status == "error" { err = errors.New(res.Error.Message) } return res, err }