Skip to content

Commit 75fc7f8

Browse files
author
AudD
committed
Initial release v1.4.0
0 parents  commit 75fc7f8

33 files changed

Lines changed: 6195 additions & 0 deletions

.github/workflows/ci.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
test:
11+
name: tests + clippy + fmt
12+
runs-on: ubuntu-latest
13+
strategy:
14+
fail-fast: false
15+
matrix:
16+
rust: ['1.75.0', 'stable', 'beta']
17+
steps:
18+
- uses: actions/checkout@v4
19+
- uses: dtolnay/rust-toolchain@master
20+
with:
21+
toolchain: ${{ matrix.rust }}
22+
components: rustfmt, clippy
23+
- uses: Swatinem/rust-cache@v2
24+
- name: rustfmt
25+
if: matrix.rust == 'stable'
26+
run: cargo fmt --check
27+
- name: clippy
28+
if: matrix.rust == 'stable'
29+
run: cargo clippy --all-targets -- -D warnings
30+
- name: cargo build
31+
run: cargo build
32+
- name: cargo test
33+
run: cargo test --all-features --no-fail-fast
34+
- name: cargo doc
35+
if: matrix.rust == 'stable'
36+
run: cargo doc --no-deps --all-features
37+
env:
38+
RUSTDOCFLAGS: -D warnings

.github/workflows/contract.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: Contract tests
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
schedule:
9+
- cron: '0 6 * * *' # daily at 06:00 UTC
10+
repository_dispatch:
11+
types: [openapi-updated]
12+
13+
jobs:
14+
contract:
15+
name: validate parser against latest audd-openapi fixtures
16+
runs-on: ubuntu-latest
17+
steps:
18+
- uses: actions/checkout@v4
19+
with:
20+
path: audd-rust
21+
- name: Check out audd-openapi
22+
uses: actions/checkout@v4
23+
with:
24+
repository: AudDMusic/audd-openapi
25+
path: audd-openapi
26+
ref: main
27+
- uses: dtolnay/rust-toolchain@stable
28+
- uses: Swatinem/rust-cache@v2
29+
with:
30+
workspaces: audd-rust
31+
- name: Run contract tests
32+
working-directory: audd-rust
33+
env:
34+
AUDD_OPENAPI_FIXTURES: ${{ github.workspace }}/audd-openapi/fixtures
35+
run: cargo test --test contract -- --nocapture
36+
- name: Open issue on failure (dispatched runs only)
37+
if: failure() && github.event_name == 'repository_dispatch'
38+
env:
39+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
40+
TRIGGER_SHA: ${{ github.event.client_payload.trigger_sha }}
41+
run: |
42+
gh issue create \
43+
--title "Contract drift: audd-openapi spec change broke parser" \
44+
--body "An openapi-updated dispatch (trigger SHA: $TRIGGER_SHA) caused contract tests to fail. Investigate and update parsers." \
45+
--label "contract-drift" || true

.github/workflows/release.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'audd-rust/v*'
7+
8+
permissions:
9+
contents: read
10+
id-token: write
11+
attestations: write
12+
13+
jobs:
14+
publish:
15+
name: cargo publish
16+
runs-on: ubuntu-latest
17+
environment: crates-io
18+
steps:
19+
- uses: actions/checkout@v4
20+
- uses: dtolnay/rust-toolchain@stable
21+
- uses: Swatinem/rust-cache@v2
22+
- name: Verify the crate builds
23+
run: cargo build --release
24+
- name: cargo package (sanity)
25+
run: cargo package --no-verify
26+
- name: Generate Sigstore attestations
27+
uses: actions/attest-build-provenance@v1
28+
with:
29+
subject-path: 'target/package/audd-*.crate'
30+
- name: cargo publish
31+
run: cargo publish --token ${{ secrets.CRATES_IO_TOKEN }}

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/target
2+
/Cargo.lock
3+
**/*.rs.bk
4+
.DS_Store

CHANGELOG.md

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [1.4.0] - 2026-05-05
9+
10+
### Changed
11+
12+
- Brand rename across all PascalCase types: the main client and its sibling
13+
types now spell the brand as `AudD`. `AudD`, `AudDBuilder`, `AudDError`,
14+
`AudDEvent`. The crate name `audd` (lowercase) and the `AUDD_API_TOKEN`
15+
environment variable are unchanged.
16+
17+
## [1.3.0] - 2026-05-05
18+
19+
Coordinated v1.3.0 stable release across the audd-sdks family. No breaking
20+
changes; the version bump signals API stability across all nine SDKs.
21+
22+
The full v0.3.0 polish — env-var auto-pickup, streaming/preview helpers
23+
with metadata fallback, `onEvent` inspection hook, thread-safe token
24+
rotation, plus per-language work (JPMS module-info, Kotlin `Flow<LongpollEvent>`,
25+
Swift `Sendable` + DocC, .NET AOT/source-gen + `IServiceCollection`, Rust
26+
TLS feature flags + `Serialize`, PHP PSR-3 logger, Python `__repr__` +
27+
`pretty_print()`, Go `slog` example) is now the v1.3.0 baseline.
28+
29+
## [0.3.0] - 2026-05-05
30+
31+
### Added
32+
33+
- TLS-backend feature flags. `default = ["rustls-tls"]` keeps the v0.2 behavior
34+
(pure-Rust TLS + Mozilla CA bundle) intact for existing users; opt into
35+
`native-tls` (system OpenSSL — corp CA bundles, OpenSSL FIPS, etc.) or
36+
`vendored-openssl` (static OpenSSL build, no `libssl-dev` required) by
37+
setting `default-features = false` and naming the backend explicitly. See
38+
the README's "Choosing a TLS backend" section.
39+
- `Serialize` derive on every public model — `RecognitionResult`,
40+
`AppleMusicMetadata`, `SpotifyMetadata`, `DeezerMetadata`, `NapsterMetadata`,
41+
`MusicBrainzEntry`, `EnterpriseMatch`, `EnterpriseChunkResult`, `Stream`,
42+
`StreamCallbackPayload`, `StreamCallbackResult`, `StreamCallbackResultEntry`,
43+
`StreamCallbackNotification`, `LyricsResult`, `RecognitionMatch`,
44+
`StreamingProvider`, `AudDEvent`, `EventKind`. Round-trip recognition
45+
results into your own logs / queues / databases without a manual mapper.
46+
`RecognitionMatch` serializes as a serde-tagged enum
47+
(`{"kind": "public" | "custom", "result": ...}`); `StreamingProvider` /
48+
`EventKind` serialize to their wire-name strings.
49+
50+
### Changed
51+
52+
- `reqwest` is now pulled with `default-features = false` plus the
53+
SDK-managed feature gate. The `multipart` / `json` / `stream` feature set
54+
is unchanged from v0.2.
55+
56+
## [0.2.0] - 2026-05-05
57+
58+
### Added
59+
60+
- `AUDD_API_TOKEN` environment-variable fallback in `AudD::new` /
61+
`AudD::builder().build()` and a new `AudD::from_env()` constructor. When the
62+
token argument is empty and `AUDD_API_TOKEN` is unset, `build()` returns
63+
`AudDError::Configuration` pointing at <https://dashboard.audd.io>.
64+
- `RecognitionResult::streaming_url(StreamingProvider)`,
65+
`RecognitionResult::streaming_urls()`, `RecognitionResult::preview_url()`,
66+
`EnterpriseMatch::streaming_url`, and `EnterpriseMatch::streaming_urls`
67+
resolution prefers a direct URL from the relevant metadata block, falling
68+
back to the `lis.tn` `?<provider>` redirect helper. New `StreamingProvider`
69+
enum (`Spotify` / `AppleMusic` / `Deezer` / `Napster` / `YouTube`).
70+
- `AudD::set_api_token(&str)` thread-safe rotation backed by `Arc<RwLock>`
71+
on both the standard and enterprise transports. Rejects empty tokens with
72+
`AudDError::Configuration`. `AudD::api_token()` now returns `String`.
73+
- `AudD::on_event(...)` inspection hook with `AudDEvent` (`kind`, `method`,
74+
`url`, `request_id`, `http_status`, `elapsed`, `error_code`, `extras`).
75+
Hook panics caught by `std::panic::catch_unwind`. `api_token` and request /
76+
response bodies are never included.
77+
78+
### Changed
79+
80+
- New `AudDError::Configuration` variant for construction-time misuse.
81+
82+
### Removed
83+
84+
- Stale `advanced_lyrics` example target reference (per directive: no
85+
ready-made find-lyrics example).
86+
87+
## [0.1.0] - 2026-05-04
88+
89+
### Added
90+
91+
- First public release of the official Rust SDK for the AudD music recognition API.
92+
- Async-only client (`AudD`) backed by `reqwest` + `tokio`.
93+
- `recognize` (URL / path / bytes / async reader) returning `Option<RecognitionResult>`.
94+
- `recognize_enterprise` returning `Vec<EnterpriseMatch>` with hour-long timeouts.
95+
- `streams.*` namespace covering set/get callback URL, add/list/set_url/delete, longpoll
96+
with default-on preflight (and `skip_callback_check` opt-out), `derive_longpoll_category`,
97+
and `parse_callback`.
98+
- `custom_catalog.add` with override-message handling for code 904.
99+
- `advanced.find_lyrics` and `advanced.raw_request` escape hatch.
100+
- Tokenless `LongpollConsumer` (top-level export) with READ-class retries, configurable
101+
`max_attempts` and `backoff_factor`, and HTTP-vs-JSON error distinction.
102+
- `AudDError` typed error enum with `is_authentication()` / `is_quota()` / etc. helpers,
103+
branded-message extraction, and code-51 deprecation pass-through (emitted via `tracing::warn!`).
104+
- Forward-compatible models — every type carries `#[serde(flatten)] extras` and
105+
`raw_response`.
106+
- Per-attempt source re-opener pattern (`prepare_source`) so retries always send a fresh
107+
multipart body.
108+
- `RecognitionMatch` enum (`Public` / `Custom`) for exhaustive pattern matching.
109+
- Built against [audd-openapi](https://github.com/AudDMusic/audd-openapi) v0.1.0 fixtures.

Cargo.toml

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
[package]
2+
name = "audd"
3+
version = "1.4.0"
4+
edition = "2021"
5+
rust-version = "1.75"
6+
license = "MIT"
7+
description = "Official Rust SDK for the AudD music recognition API"
8+
repository = "https://github.com/AudDMusic/audd-rust"
9+
homepage = "https://audd.io"
10+
documentation = "https://docs.rs/audd"
11+
keywords = ["audd", "music", "recognition", "audio", "fingerprint"]
12+
categories = ["api-bindings", "multimedia::audio"]
13+
readme = "README.md"
14+
exclude = ["tests/integration*", ".github/*"]
15+
16+
[features]
17+
# `rustls-tls` is the default and matches the v0.2 behavior (Mozilla CA bundle,
18+
# pure-Rust TLS stack). Opt out with `default-features = false` and enable
19+
# `native-tls` (or `vendored-openssl`) when you need OpenSSL — corp environments
20+
# with custom CA trust stores, OpenSSL FIPS, etc.
21+
default = ["rustls-tls"]
22+
rustls-tls = ["reqwest/rustls-tls"]
23+
native-tls = ["reqwest/native-tls"]
24+
# Statically links a vendored copy of OpenSSL — useful when the build host
25+
# lacks `libssl-dev` / pkg-config OpenSSL headers but you still need the
26+
# OpenSSL TLS stack at runtime.
27+
vendored-openssl = ["reqwest/native-tls", "reqwest/native-tls-vendored"]
28+
# Opt-in live-API integration tests; gate via env var AUDD_API_TOKEN.
29+
integration = []
30+
31+
[dependencies]
32+
reqwest = { version = "0.12", default-features = false, features = ["multipart", "json", "stream"] }
33+
serde = { version = "1", features = ["derive"] }
34+
serde_json = "1"
35+
tokio = { version = "1", features = ["rt-multi-thread", "macros", "fs", "io-util", "sync", "time"] }
36+
thiserror = "1"
37+
tracing = "0.1"
38+
futures-core = "0.3"
39+
async-stream = "0.3"
40+
tokio-util = { version = "0.7", features = ["io"] }
41+
md5 = "0.7"
42+
url = "2"
43+
44+
[dev-dependencies]
45+
tokio = { version = "1", features = ["rt-multi-thread", "macros", "fs", "io-util", "sync", "time", "test-util"] }
46+
tokio-test = "0.4"
47+
wiremock = "0.6"
48+
serde_json = "1"
49+
tempfile = "3"
50+
futures-util = "0.3"
51+
52+
[[example]]
53+
name = "recognize_url"
54+
path = "examples/recognize_url.rs"
55+
56+
[[example]]
57+
name = "recognize_file"
58+
path = "examples/recognize_file.rs"
59+
60+
[[example]]
61+
name = "recognize_enterprise"
62+
path = "examples/recognize_enterprise.rs"
63+
64+
[[example]]
65+
name = "streams_setup"
66+
path = "examples/streams_setup.rs"
67+
68+
[[example]]
69+
name = "streams_longpoll"
70+
path = "examples/streams_longpoll.rs"
71+
72+
[[example]]
73+
name = "streams_callback_handler"
74+
path = "examples/streams_callback_handler.rs"
75+
76+
[[example]]
77+
name = "custom_catalog_add"
78+
path = "examples/custom_catalog_add.rs"
79+
80+
[[example]]
81+
name = "tokenless_longpoll"
82+
path = "examples/tokenless_longpoll.rs"

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 AudD
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

0 commit comments

Comments
 (0)