Audd
Unofficial ruby sdk for AudD music recognition api. https://docs.audd.io/
I've only implemented the parts of the api that I use, please open prs to contribute any additional functionality you would like.
Installation
Install the gem and add to the application's Gemfile by executing:
bundle add audd
If bundler is not being used to manage dependencies, install the gem by executing:
gem install audd
Usage
Recognize a song
api_token = "your_token"
audd = Audd.new(api_token)
# read https://docs.audd.io/#recognize to learn about request options.
request = audd.recognize(file: file) # one of file: file or url: url
.(:apple_music, :musicbrainz, :spotify, :deezer)
.market("us")
result = request.execute!
file: takes a path, a Pathname, or an open IO; url: takes an https url that
AudD downloads itself. Pass exactly one of them.
Nothing is sent until execute!, which returns an Audd::RecognitionResult — or
nil when the audio was processed fine but didn't match anything. That is a
successful response, not an error.
result.title #=> "Everybody Wants To Rule The World"
result.artist #=> "Tears For Fears"
result.timecode #=> "00:56" — where in the song the matched fragment plays
result.apple_music #=> Audd::AppleMusicMetadata
result.public_match? #=> true (false for matches against your own catalog)
The response classes are plain objects named after the AudD OpenAPI
schemas, namespaced under Audd:
RecognitionResult, AppleMusicMetadata, SpotifyMetadata, DeezerMetadata,
NapsterMetadata and MusicBrainzEntry. Those schemas all allow extra
properties and AudD passes provider payloads through verbatim, so any key the
gem doesn't map is still reachable — result.apple_music["hasLyrics"] — and the
whole payload is on #raw.
Only recognize is implemented. Audd::Client#recognize_enterprise and
Audd::Client#find_lyrics raise NotImplementedError.
Timeouts
Because the recognize endpoint holds a long request open, the timeout for that endpoint is 60 seconds
- make sure not to make this request inside of an http transaction.
Override it per request with .timeout(seconds). On expiry you get an
Audd::TimeoutError. Note that AudD meters the request server-side whether or
not you wait for the answer.
Errors
Everything raised descends from Audd::Error, so one rescue catches the lot:
Audd::Error
├── Audd::ConfigurationError # no api_token given and AUDD_API_TOKEN unset
├── Audd::InvalidParameterError # bad arguments — raised before anything is sent
├── Audd::ConnectionError # network, DNS, or TLS failure; nothing was received
│ └── Audd::TimeoutError # the request outran its timeout
├── Audd::SerializationError # a 2xx response whose body wasn't parseable JSON
└── Audd::ApiError # the server answered status: "error"
├── Audd::AuthenticationError
├── Audd::QuotaError
├── Audd::SubscriptionError
├── Audd::InvalidRequestError
├── Audd::InvalidAudioError
├── Audd::StreamLimitError
├── Audd::RateLimitError
├── Audd::NotReleasedError
├── Audd::BlockedError
├── Audd::NeedsUpdateError
└── Audd::ServerError
Audd::ConfigurationError and Audd::InvalidParameterError are raised locally,
before any HTTP happens — a missing token, neither or both of file:/url:, an
unreadable path, or a return_metadata source AudD doesn't accept.
The rest of the hierarchy comes from the server. Each AudD error code maps to one class:
| Code(s) | Class | Meaning |
|---|---|---|
| 900, 901, 903 | Audd::AuthenticationError |
The api_token is missing, wrong, or inactive |
| 902 | Audd::QuotaError |
Quota or per-copy limit reached |
| 904, 905 | Audd::SubscriptionError |
The endpoint isn't available on this plan |
| 50, 51, 600, 601, 602, 700, 701, 702, 906 | Audd::InvalidRequestError |
Bad input — no file or url sent, malformed parameters |
| 300, 400, 500 | Audd::InvalidAudioError |
The audio itself couldn't be read or fingerprinted |
| 610 | Audd::StreamLimitError |
Subscription stream slots exhausted |
| 611 | Audd::RateLimitError |
Per-stream daily rate limit |
| 907 | Audd::NotReleasedError |
The song hasn't been released yet |
| 19, 31337 | Audd::BlockedError |
Security, abuse, sanctions, IP ban, or maintenance |
| 20 | Audd::NeedsUpdateError |
Client needs updating / paid version required |
| 100, 1000, anything else | Audd::ServerError |
Upstream failure, and every code this gem doesn't recognise |
Code 51 is the exception to the rule: it's a soft deprecation warning. When the server sends it and still returns a result, the gem warns on stderr and hands you the result instead of raising.
Every Audd::ApiError carries error_code, error_message, http_status,
request_id, request_params, request_method, branded_message and
raw_response — enough to log an incident or open a ticket with AudD support.
begin
result = audd.recognize(file: file).execute!
rescue Audd::AuthenticationError => e
abort "check your token: #{e.}"
rescue Audd::InvalidAudioError => e
warn "we sent something unusable: #{e.}"
rescue Audd::ApiError => e
warn "AudD ##{e.error_code}: #{e.} (request_id=#{e.request_id})"
end
Development
After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.
Testing
We use contract testing based on the audd openapi https://github.com/AudDMusic/audd-openapi library.
It's vendored as a git submodule at spec/audd-openapi, pinned to a tag (v1.4.4)
so the contract can't move under us without a reviewable diff. Fetch it with:
git submodule update --init
The contract specs read both the spec document — to check we only send the form
fields POST / documents, and that every error code it enumerates maps to an
exception class — and the captured response fixtures, which they replay through
the real client. Without the submodule those specs skip rather than fail, so the
rest of the suite still runs on a fresh clone.
To take a new spec version: update the submodule to the new tag, bump
OpenAPI::PINNED_VERSION in spec/support/openapi.rb, and run rake.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/RowanMcDonald /audd. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.
License
The gem is available as open source under the terms of the MIT License.
Code of Conduct
Everyone interacting in the Audd project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.