mirror of
https://github.com/librespot-org/librespot.git
synced 2025-10-02 17:29:22 +02:00
feat: add configurable TLS backend selection with native-tls as default (#1541)
Add support for choosing between native-tls and rustls-tls backends through feature flags, with native-tls as the default for maximum platform compatibility. Key changes: - Add mutually exclusive native-tls and rustls-tls feature flags - Use conditional compilation to select TLS implementation - Configure rustls-tls with platform certificate verifier - Refactor to workspace-based dependency management - Update CI workflows with improved cross-compilation support - Add comprehensive TLS backend documentation The native-tls backend uses system TLS libraries (OpenSSL on Linux, Secure Transport on macOS, SChannel on Windows) while rustls-tls provides a pure Rust implementation with platform certificate stores.
This commit is contained in:
parent
03bcdc6bda
commit
0a4969ffe2
31 changed files with 928 additions and 577 deletions
|
@ -8,7 +8,6 @@ ENV CARGO_REGISTRIES_CRATES_IO_PROTOCOL="sparse"
|
|||
ENV RUST_BACKTRACE=1
|
||||
ENV RUSTFLAGS="-D warnings"
|
||||
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
git \
|
||||
|
|
|
@ -7,7 +7,6 @@ ENV CARGO_REGISTRIES_CRATES_IO_PROTOCOL="sparse"
|
|||
ENV RUST_BACKTRACE=1
|
||||
ENV RUSTFLAGS="-D warnings -C target-feature=-crt-static"
|
||||
|
||||
|
||||
RUN apk add --no-cache \
|
||||
git \
|
||||
nano\
|
||||
|
|
|
@ -1,24 +1,20 @@
|
|||
{
|
||||
"name": "Librespot Devcontainer",
|
||||
"dockerFile": "Dockerfile.alpine",
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
//"postCreateCommand": "",
|
||||
"customizations": {
|
||||
// Configure properties specific to VS Code.
|
||||
"vscode": {
|
||||
"settings": {
|
||||
"dev.containers.copyGitConfig": true
|
||||
},
|
||||
"extensions": [
|
||||
"eamodio.gitlens",
|
||||
"github.vscode-github-actions",
|
||||
"rust-lang.rust-analyzer"
|
||||
]
|
||||
}
|
||||
},
|
||||
"_postCreateCommand_comment": "Uncomment 'postCreateCommand' to run commands after the container is created.",
|
||||
"_postCreateCommand": "",
|
||||
"customizations": {
|
||||
"_comment": "Configure properties specific to VS Code.",
|
||||
"vscode": {
|
||||
"settings": {
|
||||
"dev.containers.copyGitConfig": true
|
||||
},
|
||||
"extensions": ["eamodio.gitlens", "github.vscode-github-actions", "rust-lang.rust-analyzer"]
|
||||
}
|
||||
},
|
||||
"containerEnv": {
|
||||
"GIT_EDITOR": "nano"
|
||||
}
|
||||
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||
// "remoteUser": "root"
|
||||
}
|
||||
},
|
||||
"_remoteUser_comment": "Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root",
|
||||
"_remoteUser": "root"
|
||||
}
|
||||
|
|
99
.github/workflows/build.yml
vendored
Normal file
99
.github/workflows/build.yml
vendored
Normal file
|
@ -0,0 +1,99 @@
|
|||
---
|
||||
# Note, this is used in the badge URL!
|
||||
name: build
|
||||
|
||||
"on":
|
||||
push:
|
||||
branches: [dev, master]
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
- "docs/**"
|
||||
- "contrib/**"
|
||||
- "LICENSE"
|
||||
- "*.sh"
|
||||
- "**/Dockerfile*"
|
||||
- "publish.sh"
|
||||
- "test.sh"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
- "docs/**"
|
||||
- "contrib/**"
|
||||
- "LICENSE"
|
||||
- "*.sh"
|
||||
- "**/Dockerfile*"
|
||||
- "publish.sh"
|
||||
- "test.sh"
|
||||
schedule:
|
||||
# Run CI every week
|
||||
- cron: "00 01 * * 0"
|
||||
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
RUSTFLAGS: -D warnings
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: cargo +${{ matrix.toolchain }} test (${{ matrix.os }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
toolchain:
|
||||
- "1.85" # MSRV (Minimum supported rust version)
|
||||
- stable
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: ${{ matrix.toolchain }}
|
||||
|
||||
- name: Cache Rust dependencies
|
||||
uses: Swatinem/rust-cache@v2
|
||||
|
||||
- name: Install developer package dependencies (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
run: >
|
||||
sudo apt-get update && sudo apt-get install -y
|
||||
libpulse-dev portaudio19-dev libasound2-dev libsdl2-dev
|
||||
gstreamer1.0-dev libgstreamer-plugins-base1.0-dev
|
||||
libavahi-compat-libdnssd-dev
|
||||
|
||||
- name: Fetch dependencies
|
||||
run: cargo fetch --locked
|
||||
|
||||
- name: Build workspace with examples
|
||||
run: cargo build --frozen --workspace --examples
|
||||
|
||||
- name: Run tests
|
||||
run: cargo test --workspace
|
||||
|
||||
- name: Install cargo-hack
|
||||
uses: taiki-e/install-action@cargo-hack
|
||||
|
||||
- name: Check packages without TLS requirements
|
||||
run: cargo hack check -p librespot-protocol --each-feature
|
||||
|
||||
- name: Check workspace with native-tls
|
||||
run: >
|
||||
cargo hack check -p librespot --each-feature --exclude-all-features
|
||||
--include-features native-tls --exclude-features rustls-tls
|
||||
|
||||
- name: Check workspace with rustls-tls
|
||||
run: >
|
||||
cargo hack check -p librespot --each-feature --exclude-all-features
|
||||
--include-features rustls-tls --exclude-features native-tls
|
||||
|
||||
- name: Build binary with default features
|
||||
run: cargo build --frozen
|
||||
|
||||
- name: Upload debug artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: librespot-${{ matrix.os }}-${{ matrix.toolchain }}
|
||||
path: >
|
||||
target/debug/librespot${{ runner.os == 'Windows' && '.exe' || '' }}
|
||||
if-no-files-found: error
|
78
.github/workflows/cross-compile.yml
vendored
Normal file
78
.github/workflows/cross-compile.yml
vendored
Normal file
|
@ -0,0 +1,78 @@
|
|||
---
|
||||
name: cross-compile
|
||||
|
||||
"on":
|
||||
push:
|
||||
branches: [dev, master]
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
- "docs/**"
|
||||
- "contrib/**"
|
||||
- "LICENSE"
|
||||
- "*.sh"
|
||||
- "**/Dockerfile*"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
- "docs/**"
|
||||
- "contrib/**"
|
||||
- "LICENSE"
|
||||
- "*.sh"
|
||||
- "**/Dockerfile*"
|
||||
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
RUSTFLAGS: -D warnings
|
||||
|
||||
jobs:
|
||||
cross-compile:
|
||||
name: cross +${{ matrix.toolchain }} build ${{ matrix.platform.target }}
|
||||
runs-on: ${{ matrix.platform.runs-on }}
|
||||
continue-on-error: false
|
||||
strategy:
|
||||
matrix:
|
||||
platform:
|
||||
- arch: armv7
|
||||
runs-on: ubuntu-latest
|
||||
target: armv7-unknown-linux-gnueabihf
|
||||
|
||||
- arch: aarch64
|
||||
runs-on: ubuntu-latest
|
||||
target: aarch64-unknown-linux-gnu
|
||||
|
||||
- arch: riscv64gc
|
||||
runs-on: ubuntu-latest
|
||||
target: riscv64gc-unknown-linux-gnu
|
||||
|
||||
toolchain:
|
||||
- "1.85" # MSRV (Minimum Supported Rust Version)
|
||||
- stable
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Build binary with default features
|
||||
if: matrix.platform.target != 'riscv64gc-unknown-linux-gnu'
|
||||
uses: houseabsolute/actions-rust-cross@v1
|
||||
with:
|
||||
command: build
|
||||
target: ${{ matrix.platform.target }}
|
||||
toolchain: ${{ matrix.toolchain }}
|
||||
args: --locked --verbose
|
||||
|
||||
- name: Build binary with rustls-tls and no default features
|
||||
if: matrix.platform.target == 'riscv64gc-unknown-linux-gnu'
|
||||
uses: houseabsolute/actions-rust-cross@v1
|
||||
with:
|
||||
command: build
|
||||
target: ${{ matrix.platform.target }}
|
||||
toolchain: ${{ matrix.toolchain }}
|
||||
args: --locked --verbose --no-default-features --features rustls-tls
|
||||
|
||||
- name: Upload debug artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: librespot-${{ matrix.platform.runs-on }}-${{ matrix.platform.arch }}-${{ matrix.toolchain }} # yamllint disable-line rule:line-length
|
||||
path: target/${{ matrix.platform.target }}/debug/librespot
|
||||
if-no-files-found: error
|
79
.github/workflows/quality.yml
vendored
Normal file
79
.github/workflows/quality.yml
vendored
Normal file
|
@ -0,0 +1,79 @@
|
|||
---
|
||||
name: code-quality
|
||||
|
||||
"on":
|
||||
push:
|
||||
branches: [dev, master]
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
- "docs/**"
|
||||
- "contrib/**"
|
||||
- "LICENSE"
|
||||
- "*.sh"
|
||||
- "**/Dockerfile*"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
- "docs/**"
|
||||
- "contrib/**"
|
||||
- "LICENSE"
|
||||
- "*.sh"
|
||||
- "**/Dockerfile*"
|
||||
schedule:
|
||||
# Run CI every week
|
||||
- cron: "00 01 * * 0"
|
||||
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
RUSTFLAGS: -D warnings
|
||||
|
||||
jobs:
|
||||
fmt:
|
||||
name: cargo fmt
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Check formatting
|
||||
run: cargo fmt --all -- --check
|
||||
|
||||
clippy:
|
||||
needs: fmt
|
||||
name: cargo clippy
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Cache Rust dependencies
|
||||
uses: Swatinem/rust-cache@v2
|
||||
|
||||
- name: Install developer package dependencies
|
||||
run: >
|
||||
sudo apt-get update && sudo apt-get install -y
|
||||
libpulse-dev portaudio19-dev libasound2-dev libsdl2-dev
|
||||
gstreamer1.0-dev libgstreamer-plugins-base1.0-dev
|
||||
libavahi-compat-libdnssd-dev
|
||||
|
||||
- name: Install cargo-hack
|
||||
uses: taiki-e/install-action@cargo-hack
|
||||
|
||||
- name: Run clippy on packages without TLS requirements
|
||||
run: cargo hack clippy -p librespot-protocol --each-feature
|
||||
|
||||
- name: Run clippy with native-tls
|
||||
run: >
|
||||
cargo hack clippy -p librespot --each-feature --exclude-all-features
|
||||
--include-features native-tls --exclude-features rustls-tls
|
||||
|
||||
- name: Run clippy with rustls-tls
|
||||
run: >
|
||||
cargo hack clippy -p librespot --each-feature --exclude-all-features
|
||||
--include-features rustls-tls --exclude-features native-tls
|
281
.github/workflows/test.yml
vendored
281
.github/workflows/test.yml
vendored
|
@ -1,281 +0,0 @@
|
|||
# Note, this is used in the badge URL!
|
||||
name: test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [dev, master]
|
||||
paths:
|
||||
[
|
||||
"**.rs",
|
||||
"Cargo.toml",
|
||||
"Cargo.lock",
|
||||
"rustfmt.toml",
|
||||
".github/workflows/*",
|
||||
"!*.md",
|
||||
"!contrib/*",
|
||||
"!docs/*",
|
||||
"!LICENSE",
|
||||
"!*.sh",
|
||||
]
|
||||
pull_request:
|
||||
paths:
|
||||
[
|
||||
"**.rs",
|
||||
"Cargo.toml",
|
||||
"Cargo.lock",
|
||||
"rustfmt.toml",
|
||||
".github/workflows/*",
|
||||
"!*.md",
|
||||
"!contrib/*",
|
||||
"!docs/*",
|
||||
"!LICENSE",
|
||||
"!*.sh",
|
||||
]
|
||||
schedule:
|
||||
# Run CI every week
|
||||
- cron: "00 01 * * 0"
|
||||
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
RUSTFLAGS: -D warnings
|
||||
|
||||
# The layering here is as follows:
|
||||
# 1. code formatting
|
||||
# 2. absence of lints
|
||||
# 3. absence of errors and warnings on Linux/x86
|
||||
# 4. cross compilation on Windows and Linux/ARM
|
||||
|
||||
jobs:
|
||||
fmt:
|
||||
name: cargo fmt
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
- name: Install toolchain
|
||||
run: curl https://sh.rustup.rs -sSf | sh -s -- --profile default --default-toolchain stable -y
|
||||
- run: cargo fmt --all -- --check
|
||||
|
||||
clippy:
|
||||
needs: fmt
|
||||
name: cargo +${{ matrix.toolchain }} clippy (${{ matrix.os }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
continue-on-error: false
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
toolchain: [stable]
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install toolchain
|
||||
run: curl https://sh.rustup.rs -sSf | sh -s -- --profile default --default-toolchain ${{ matrix.toolchain }} -y
|
||||
|
||||
- name: Get Rustc version
|
||||
id: get-rustc-version
|
||||
run: echo "version=$(rustc -V)" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Cache Rust dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry/index
|
||||
~/.cargo/registry/cache
|
||||
~/.cargo/git
|
||||
target
|
||||
key: ${{ runner.os }}-${{ steps.get-rustc-version.outputs.version }}-${{ hashFiles('Cargo.lock') }}
|
||||
|
||||
- name: Install developer package dependencies
|
||||
run: sudo apt-get update && sudo apt install -y libunwind-dev && sudo apt-get install libpulse-dev portaudio19-dev libasound2-dev libsdl2-dev gstreamer1.0-dev libgstreamer-plugins-base1.0-dev libavahi-compat-libdnssd-dev
|
||||
|
||||
- run: cargo install cargo-hack
|
||||
- run: cargo hack --workspace --remove-dev-deps
|
||||
- run: cargo clippy -p librespot-core --no-default-features
|
||||
- run: cargo clippy -p librespot-core
|
||||
- run: cargo hack clippy --each-feature -p librespot-discovery
|
||||
- run: cargo hack clippy --each-feature -p librespot-playback
|
||||
- run: cargo hack clippy --each-feature
|
||||
|
||||
test-linux:
|
||||
name: cargo +${{ matrix.toolchain }} check (${{ matrix.os }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
continue-on-error: ${{ matrix.experimental }}
|
||||
needs: clippy
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
toolchain:
|
||||
- "1.85" # MSRV (Minimum supported rust version)
|
||||
- stable
|
||||
experimental: [false]
|
||||
# Ignore failures in beta
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
toolchain: beta
|
||||
experimental: true
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install toolchain
|
||||
run: curl https://sh.rustup.rs -sSf | sh -s -- --profile minimal --default-toolchain ${{ matrix.toolchain }} -y
|
||||
|
||||
- name: Get Rustc version
|
||||
id: get-rustc-version
|
||||
run: echo "version=$(rustc -V)" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Cache Rust dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry/index
|
||||
~/.cargo/registry/cache
|
||||
~/.cargo/git
|
||||
target
|
||||
key: ${{ runner.os }}-${{ steps.get-rustc-version.outputs.version }}-${{ hashFiles('Cargo.lock') }}
|
||||
|
||||
- name: Install developer package dependencies
|
||||
run: sudo apt-get update && sudo apt install -y libunwind-dev && sudo apt-get install libpulse-dev portaudio19-dev libasound2-dev libsdl2-dev gstreamer1.0-dev libgstreamer-plugins-base1.0-dev libavahi-compat-libdnssd-dev
|
||||
|
||||
- run: cargo fetch --locked
|
||||
- run: cargo build --frozen --workspace --examples
|
||||
- run: cargo test --workspace
|
||||
|
||||
- run: cargo install cargo-hack
|
||||
- run: cargo hack --workspace --remove-dev-deps
|
||||
- run: cargo check -p librespot-core --no-default-features
|
||||
- run: cargo check -p librespot-core
|
||||
- run: cargo hack check --each-feature -p librespot-discovery
|
||||
- run: cargo hack check --each-feature -p librespot-playback
|
||||
- run: cargo hack check --each-feature
|
||||
|
||||
test-windows:
|
||||
needs: clippy
|
||||
name: cargo +${{ matrix.toolchain }} check (${{ matrix.os }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
continue-on-error: false
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [windows-latest]
|
||||
toolchain:
|
||||
- "1.85" # MSRV (Minimum supported rust version)
|
||||
- stable
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install toolchain
|
||||
run: curl https://sh.rustup.rs -sSf | sh -s -- --profile minimal --default-toolchain ${{ matrix.toolchain }} -y
|
||||
|
||||
- name: Get Rustc version
|
||||
id: get-rustc-version
|
||||
run: echo "version=$(rustc -V)" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Cache Rust dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry/index
|
||||
~/.cargo/registry/cache
|
||||
~/.cargo/git
|
||||
target
|
||||
key: ${{ runner.os }}-${{ steps.get-rustc-version.outputs.version }}-${{ hashFiles('Cargo.lock') }}
|
||||
|
||||
- run: cargo fetch --locked
|
||||
- run: cargo build --frozen --workspace --examples
|
||||
- run: cargo test --workspace
|
||||
|
||||
- run: cargo install cargo-hack
|
||||
- run: cargo hack --workspace --remove-dev-deps
|
||||
- run: cargo check --no-default-features
|
||||
- run: cargo check
|
||||
|
||||
test-cross-linux:
|
||||
name: cross +${{ matrix.toolchain }} build ${{ matrix.target }}
|
||||
needs: clippy
|
||||
runs-on: ${{ matrix.os }}
|
||||
continue-on-error: false
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
target:
|
||||
- armv7-unknown-linux-gnueabihf
|
||||
- aarch64-unknown-linux-gnu
|
||||
- riscv64gc-unknown-linux-gnu
|
||||
toolchain:
|
||||
- "1.85" # MSRV (Minimum supported rust version)
|
||||
- stable
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install toolchain
|
||||
run: curl https://sh.rustup.rs -sSf | sh -s -- --profile minimal --default-toolchain ${{ matrix.toolchain }} -y
|
||||
|
||||
- name: Get Rustc version
|
||||
id: get-rustc-version
|
||||
run: echo "version=$(rustc -V)" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Cache Rust dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry/index
|
||||
~/.cargo/registry/cache
|
||||
~/.cargo/git
|
||||
target
|
||||
key: ${{ runner.os }}-${{ matrix.target }}-${{ steps.get-rustc-version.outputs.version }}-${{ hashFiles('Cargo.lock') }}
|
||||
|
||||
- name: Install the cross compiler rust targets
|
||||
run: rustup target add ${{ matrix.target }}
|
||||
|
||||
- name: Update and Install dependencies
|
||||
run: sudo apt-get update && sudo apt-get install -y build-essential cmake libclang1
|
||||
|
||||
- name: Install bindgen-cli
|
||||
run: cargo install --force --locked bindgen-cli
|
||||
|
||||
- name: Install cross compiler
|
||||
run: |
|
||||
if [ ${{ matrix.target }} = "armv7-unknown-linux-gnueabihf" ]; then
|
||||
sudo apt-get install -y gcc-arm-linux-gnueabihf
|
||||
fi
|
||||
if [ ${{ matrix.target }} = "aarch64-unknown-linux-gnu" ]; then
|
||||
sudo apt-get install -y gcc-aarch64-linux-gnu
|
||||
fi
|
||||
if [ ${{ matrix.target }} = "riscv64gc-unknown-linux-gnu" ]; then
|
||||
sudo apt-get install -y gcc-riscv64-linux-gnu
|
||||
fi
|
||||
|
||||
- name: Set target link compiler
|
||||
run: |
|
||||
# Convert target to uppercase and replace - with _
|
||||
target=${{ matrix.target }}
|
||||
target=${target^^}
|
||||
target=${target//-/_}
|
||||
if [ ${{ matrix.target }} = "armv7-unknown-linux-gnueabihf" ]; then
|
||||
echo "CARGO_TARGET_${target}_LINKER=arm-linux-gnueabihf-gcc" >> $GITHUB_ENV
|
||||
fi
|
||||
if [ ${{ matrix.target }} = "aarch64-unknown-linux-gnu" ]; then
|
||||
echo "CARGO_TARGET_${target}_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
fi
|
||||
if [ ${{ matrix.target }} = "riscv64gc-unknown-linux-gnu" ]; then
|
||||
echo "CARGO_TARGET_${target}_LINKER=riscv64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Fetch
|
||||
run: cargo fetch --locked
|
||||
- name: Build
|
||||
run: cargo build --frozen --verbose --target ${{ matrix.target }} --no-default-features
|
||||
|
||||
- name: Check binary
|
||||
run: file target/${{ matrix.target }}/debug/librespot
|
|
@ -12,7 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- [core] MSRV is now 1.85 with Rust edition 2024 (breaking)
|
||||
- [core] AP connect and handshake have a combined 5 second timeout.
|
||||
- [core] `stream_from_cdn` now accepts the URL as `TryInto<Uri>` instead of `CdnUrl` (breaking)
|
||||
- [core] Moved from native TLS to ring and webpki on all platforms
|
||||
- [core] Add TLS backend selection with native-tls and rustls-tls options, defaulting to native-tls
|
||||
- [connect] Replaced `has_volume_ctrl` with `disable_volume` in `ConnectConfig` (breaking)
|
||||
- [connect] Changed `initial_volume` from `Option<u16>` to `u16` in `ConnectConfig` (breaking)
|
||||
- [connect] Replaced `SpircLoadCommand` with `LoadRequest`, `LoadRequestOptions` and `LoadContextOptions` (breaking)
|
||||
|
|
71
COMPILING.md
71
COMPILING.md
|
@ -67,6 +67,63 @@ Depending on the chosen backend, specific development libraries are required.
|
|||
|dns_sd | `libavahi-compat-libdnssd-dev pkg-config` | `avahi-compat-libdns_sd-devel` | |
|
||||
|libmdns (default) | | | |
|
||||
|
||||
### TLS library dependencies
|
||||
librespot requires a TLS implementation for secure connections to Spotify's servers. You can choose between two mutually exclusive options:
|
||||
|
||||
#### native-tls (default)
|
||||
Uses your system's native TLS implementation:
|
||||
- **Linux**: OpenSSL
|
||||
- **macOS**: Secure Transport (Security.framework)
|
||||
- **Windows**: SChannel (Windows TLS)
|
||||
|
||||
This is the **default choice** and provides the best compatibility. It integrates with your system's certificate store and is well-tested across platforms.
|
||||
|
||||
**When to choose native-tls:**
|
||||
- You want maximum compatibility
|
||||
- You're using system-managed certificates
|
||||
- You're on a standard Linux distribution with OpenSSL
|
||||
- You're deploying on platforms where OpenSSL is already present
|
||||
|
||||
**Dependencies:**
|
||||
On Debian/Ubuntu:
|
||||
```shell
|
||||
sudo apt-get install libssl-dev pkg-config
|
||||
```
|
||||
|
||||
On Fedora:
|
||||
```shell
|
||||
sudo dnf install openssl-devel pkg-config
|
||||
```
|
||||
|
||||
#### rustls-tls
|
||||
Uses a Rust-based TLS implementation with `rustls-platform-verifier` for certificate authority (CA) verification:
|
||||
- **Linux**: Uses system ca-certificates package
|
||||
- **macOS**: Uses Security.framework for CA verification
|
||||
- **Windows**: Uses Windows certificate store
|
||||
|
||||
**When to choose rustls-tls:**
|
||||
- You want to avoid external OpenSSL dependencies
|
||||
- You're building for reproducible/deterministic builds
|
||||
- You're targeting platforms where OpenSSL is unavailable or problematic (musl, embedded, static linking)
|
||||
- You're cross-compiling and want to avoid OpenSSL build complexity
|
||||
- You prefer having cryptographic operations implemented in Rust
|
||||
|
||||
**No additional system dependencies required** - rustls is implemented in Rust (with some assembly for performance-critical cryptographic operations) and doesn't require external libraries like OpenSSL.
|
||||
|
||||
#### Building with specific TLS backends
|
||||
```bash
|
||||
# Default (native-tls)
|
||||
cargo build
|
||||
|
||||
# Explicitly use native-tls
|
||||
cargo build --no-default-features --features "native-tls rodio-backend with-libmdns"
|
||||
|
||||
# Use rustls-tls instead
|
||||
cargo build --no-default-features --features "rustls-tls rodio-backend with-libmdns"
|
||||
```
|
||||
|
||||
**Important:** The TLS backends are mutually exclusive. Attempting to enable both will result in a compile-time error.
|
||||
|
||||
### Getting the Source
|
||||
|
||||
The recommended method is to first fork the repo, so that you have a copy that you have read/write access to. After that, it’s a simple case of cloning your fork.
|
||||
|
@ -95,19 +152,21 @@ cargo build --release
|
|||
|
||||
You will most likely want to build debug builds when developing, as they compile faster, and more verbose, and as the name suggests, are for the purposes of debugging. When submitting a bug report, it is recommended to use a debug build to capture stack traces.
|
||||
|
||||
There are also a number of compiler feature flags that you can add, in the event that you want to have certain additional features also compiled. The list of these is available on the [wiki](https://github.com/librespot-org/librespot/wiki/Compiling#addition-features).
|
||||
There are also a number of compiler feature flags that you can add, in the event that you want to have certain additional features also compiled. All available features and their descriptions are documented in the main [Cargo.toml](Cargo.toml) file. Additional platform-specific information is available on the [wiki](https://github.com/librespot-org/librespot/wiki/Compiling#addition-features).
|
||||
|
||||
By default, librespot compiles with the ```rodio-backend``` and ```with-libmdns``` features. To compile without default features, you can run with:
|
||||
By default, librespot compiles with the ```native-tls```, ```rodio-backend```, and ```with-libmdns``` features.
|
||||
|
||||
**Note:** librespot requires at least one TLS backend to function. Building with `--no-default-features` alone will fail compilation. For custom feature selection, you must specify at least one TLS backend along with your desired audio and discovery backends.
|
||||
For example, to build with the ALSA audio, libmdns discovery, and native-tls backends:
|
||||
|
||||
```bash
|
||||
cargo build --no-default-features
|
||||
cargo build --no-default-features --features "native-tls alsa-backend with-libmdns"
|
||||
```
|
||||
|
||||
Note that this will also disable zeroconf discovery backends for Spotify Connect. For normal use cases, select at least one audio and discovery backend.
|
||||
For example, to build with the ALSA audio and libmdns discovery backend:
|
||||
Or to use rustls-tls with ALSA:
|
||||
|
||||
```bash
|
||||
cargo build --no-default-features --features "alsa-backend with-libmdns"
|
||||
cargo build --no-default-features --features "rustls-tls alsa-backend with-libmdns"
|
||||
```
|
||||
|
||||
### Running
|
||||
|
|
212
Cargo.lock
generated
212
Cargo.lock
generated
|
@ -167,9 +167,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.88"
|
||||
version = "0.1.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5"
|
||||
checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -369,6 +369,16 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.7"
|
||||
|
@ -735,6 +745,21 @@ version = "0.1.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
dependencies = [
|
||||
"foreign-types-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.1"
|
||||
|
@ -1289,13 +1314,16 @@ dependencies = [
|
|||
"http",
|
||||
"hyper",
|
||||
"hyper-rustls 0.26.0",
|
||||
"hyper-tls",
|
||||
"hyper-util",
|
||||
"native-tls",
|
||||
"pin-project-lite",
|
||||
"rustls-native-certs 0.7.3",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tokio-rustls 0.25.0",
|
||||
"tower-service",
|
||||
"webpki",
|
||||
"webpki-roots 0.26.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1310,12 +1338,11 @@ dependencies = [
|
|||
"hyper-util",
|
||||
"log",
|
||||
"rustls 0.22.4",
|
||||
"rustls-native-certs",
|
||||
"rustls-native-certs 0.7.3",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
"tokio-rustls 0.25.0",
|
||||
"tower-service",
|
||||
"webpki-roots 0.26.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1327,13 +1354,29 @@ dependencies = [
|
|||
"http",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"log",
|
||||
"rustls 0.23.31",
|
||||
"rustls-pki-types",
|
||||
"rustls-platform-verifier",
|
||||
"tokio",
|
||||
"tokio-rustls 0.26.2",
|
||||
"tower-service",
|
||||
"webpki-roots 1.0.2",
|
||||
"webpki-roots",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-tls"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"native-tls",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1866,6 +1909,7 @@ dependencies = [
|
|||
"hyper",
|
||||
"hyper-proxy2",
|
||||
"hyper-rustls 0.27.7",
|
||||
"hyper-tls",
|
||||
"hyper-util",
|
||||
"librespot-oauth",
|
||||
"librespot-protocol",
|
||||
|
@ -1885,7 +1929,6 @@ dependencies = [
|
|||
"rand 0.9.2",
|
||||
"rand_distr",
|
||||
"rsa",
|
||||
"rustls 0.23.31",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha1",
|
||||
|
@ -1970,7 +2013,6 @@ dependencies = [
|
|||
"alsa",
|
||||
"cpal",
|
||||
"futures-util",
|
||||
"glib",
|
||||
"gstreamer",
|
||||
"gstreamer-app",
|
||||
"gstreamer-audio",
|
||||
|
@ -2109,6 +2151,23 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"openssl",
|
||||
"openssl-probe",
|
||||
"openssl-sys",
|
||||
"schannel",
|
||||
"security-framework 2.11.1",
|
||||
"security-framework-sys",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk"
|
||||
version = "0.9.0"
|
||||
|
@ -2304,9 +2363,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "objc2"
|
||||
version = "0.6.1"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88c6597e14493ab2e44ce58f2fdecf095a51f12ca57bec060a11c57332520551"
|
||||
checksum = "561f357ba7f3a2a61563a186a163d0a3a5247e1089524a3981d49adb775078bc"
|
||||
dependencies = [
|
||||
"objc2-encode",
|
||||
]
|
||||
|
@ -2425,12 +2484,50 @@ dependencies = [
|
|||
"pathdiff",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"openssl-macros",
|
||||
"openssl-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "option-operations"
|
||||
version = "0.5.0"
|
||||
|
@ -2917,15 +3014,16 @@ dependencies = [
|
|||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper-rustls 0.27.7",
|
||||
"hyper-tls",
|
||||
"hyper-util",
|
||||
"js-sys",
|
||||
"log",
|
||||
"native-tls",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"quinn",
|
||||
|
@ -2936,6 +3034,7 @@ dependencies = [
|
|||
"serde_urlencoded",
|
||||
"sync_wrapper",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tokio-rustls 0.26.2",
|
||||
"tower",
|
||||
"tower-http",
|
||||
|
@ -2944,7 +3043,7 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"webpki-roots 1.0.2",
|
||||
"webpki-roots",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3050,7 +3149,6 @@ version = "0.23.31"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc"
|
||||
dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
|
@ -3069,7 +3167,19 @@ dependencies = [
|
|||
"rustls-pemfile",
|
||||
"rustls-pki-types",
|
||||
"schannel",
|
||||
"security-framework",
|
||||
"security-framework 2.11.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-native-certs"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3"
|
||||
dependencies = [
|
||||
"openssl-probe",
|
||||
"rustls-pki-types",
|
||||
"schannel",
|
||||
"security-framework 3.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3091,6 +3201,33 @@ dependencies = [
|
|||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-platform-verifier"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be59af91596cac372a6942530653ad0c3a246cdd491aaa9dcaee47f88d67d5a0"
|
||||
dependencies = [
|
||||
"core-foundation 0.10.1",
|
||||
"core-foundation-sys",
|
||||
"jni",
|
||||
"log",
|
||||
"once_cell",
|
||||
"rustls 0.23.31",
|
||||
"rustls-native-certs 0.8.1",
|
||||
"rustls-platform-verifier-android",
|
||||
"rustls-webpki 0.103.4",
|
||||
"security-framework 3.3.0",
|
||||
"security-framework-sys",
|
||||
"webpki-root-certs",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-platform-verifier-android"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.102.8"
|
||||
|
@ -3179,7 +3316,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"core-foundation",
|
||||
"core-foundation 0.9.4",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"security-framework-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "3.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80fb1d92c5028aa318b4b8bd7302a5bfcf48be96a37fc6fc790f806b0004ee0c"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"core-foundation 0.10.1",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"security-framework-sys",
|
||||
|
@ -3548,7 +3698,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"core-foundation",
|
||||
"core-foundation 0.9.4",
|
||||
"system-configuration-sys",
|
||||
]
|
||||
|
||||
|
@ -3734,6 +3884,16 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-native-tls"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
|
||||
dependencies = [
|
||||
"native-tls",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.25.0"
|
||||
|
@ -3774,12 +3934,13 @@ checksum = "489a59b6730eda1b0171fcfda8b121f4bee2b35cba8645ca35c5f7ba3eb736c1"
|
|||
dependencies = [
|
||||
"futures-util",
|
||||
"log",
|
||||
"native-tls",
|
||||
"rustls 0.23.31",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tokio-rustls 0.26.2",
|
||||
"tungstenite",
|
||||
"webpki-roots 0.26.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3922,6 +4083,7 @@ dependencies = [
|
|||
"http",
|
||||
"httparse",
|
||||
"log",
|
||||
"native-tls",
|
||||
"rand 0.9.2",
|
||||
"rustls 0.23.31",
|
||||
"rustls-pki-types",
|
||||
|
@ -4006,6 +4168,12 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "vergen"
|
||||
version = "9.0.6"
|
||||
|
@ -4198,12 +4366,12 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "0.26.11"
|
||||
name = "webpki-root-certs"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9"
|
||||
checksum = "4e4ffd8df1c57e87c325000a3d6ef93db75279dc3a231125aac571650f22b12a"
|
||||
dependencies = [
|
||||
"webpki-roots 1.0.2",
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
224
Cargo.toml
224
Cargo.toml
|
@ -1,16 +1,123 @@
|
|||
[package]
|
||||
name = "librespot"
|
||||
version.workspace = true
|
||||
rust-version.workspace = true
|
||||
authors.workspace = true
|
||||
license.workspace = true
|
||||
description = "An open source client library for Spotify, with support for Spotify Connect"
|
||||
keywords = ["audio", "spotify", "music", "streaming", "connect"]
|
||||
categories = ["multimedia::audio"]
|
||||
repository.workspace = true
|
||||
readme = "README.md"
|
||||
edition.workspace = true
|
||||
include = [
|
||||
"src/**/*",
|
||||
"audio/**/*",
|
||||
"connect/**/*",
|
||||
"core/**/*",
|
||||
"discovery/**/*",
|
||||
"metadata/**/*",
|
||||
"oauth/**/*",
|
||||
"playback/**/*",
|
||||
"protocol/**/*",
|
||||
"Cargo.toml",
|
||||
"README.md",
|
||||
"LICENSE",
|
||||
"COMPILING.md",
|
||||
"CONTRIBUTING.md",
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.6.0-dev"
|
||||
rust-version = "1.85"
|
||||
authors = ["Librespot Org"]
|
||||
license = "MIT"
|
||||
description = "An open source client library for Spotify, with support for Spotify Connect"
|
||||
keywords = ["spotify"]
|
||||
repository = "https://github.com/librespot-org/librespot"
|
||||
readme = "README.md"
|
||||
edition = "2024"
|
||||
|
||||
[workspace]
|
||||
[features]
|
||||
default = ["native-tls", "rodio-backend", "with-libmdns"]
|
||||
|
||||
# TLS backends (mutually exclusive - compile-time checks in oauth/src/lib.rs)
|
||||
# Note: Feature validation is in oauth crate since it's compiled first in the dependency tree.
|
||||
# See COMPILING.md for more details on TLS backend selection.
|
||||
|
||||
# native-tls: Uses the system's native TLS stack (OpenSSL on Linux, Secure Transport on macOS,
|
||||
# SChannel on Windows). This is the default as it's well-tested, widely compatible, and integrates
|
||||
# with system certificate stores. Choose this for maximum compatibility and when you want to use
|
||||
# system-managed certificates.
|
||||
native-tls = ["librespot-core/native-tls", "librespot-oauth/native-tls"]
|
||||
|
||||
# rustls-tls: Uses the Rust-based rustls TLS implementation with platform certificate verification.
|
||||
# This provides a Rust TLS stack (with assembly optimizations) that uses rustls-platform-verifier to
|
||||
# automatically select the appropriate certificate authority (CA) certificates from your system's
|
||||
# trust store. Choose this for avoiding external OpenSSL dependencies, reproducible builds, or when
|
||||
# targeting platforms where native TLS dependencies are unavailable or problematic (musl, embedded,
|
||||
# static linking). On Linux it uses ca-certificates, on macOS it uses Security.framework, and on
|
||||
# Windows it uses the Windows certificate store.
|
||||
rustls-tls = ["librespot-core/rustls-tls", "librespot-oauth/rustls-tls"]
|
||||
|
||||
# Audio backends - see README.md for audio backend selection guide
|
||||
# Cross-platform backends:
|
||||
|
||||
# rodio-backend: Cross-platform audio backend using Rodio (default). Provides good cross-platform
|
||||
# compatibility with automatic backend selection. Uses ALSA on Linux, WASAPI on Windows, CoreAudio
|
||||
# on macOS.
|
||||
rodio-backend = ["librespot-playback/rodio-backend"]
|
||||
|
||||
# rodiojack-backend: Rodio backend with JACK support for professional audio setups.
|
||||
rodiojack-backend = ["librespot-playback/rodiojack-backend"]
|
||||
|
||||
# gstreamer-backend: Uses GStreamer multimedia framework for audio output.
|
||||
# Provides extensive audio processing capabilities.
|
||||
gstreamer-backend = ["librespot-playback/gstreamer-backend"]
|
||||
|
||||
# portaudio-backend: Cross-platform audio I/O library backend.
|
||||
portaudio-backend = ["librespot-playback/portaudio-backend"]
|
||||
|
||||
# sdl-backend: Simple DirectMedia Layer audio backend.
|
||||
sdl-backend = ["librespot-playback/sdl-backend"]
|
||||
|
||||
# Platform-specific backends:
|
||||
|
||||
# alsa-backend: Advanced Linux Sound Architecture backend (Linux only).
|
||||
# Provides low-latency audio output on Linux systems.
|
||||
alsa-backend = ["librespot-playback/alsa-backend"]
|
||||
|
||||
# pulseaudio-backend: PulseAudio backend (Linux only).
|
||||
# Integrates with the PulseAudio sound server for advanced audio routing.
|
||||
pulseaudio-backend = ["librespot-playback/pulseaudio-backend"]
|
||||
|
||||
# jackaudio-backend: JACK Audio Connection Kit backend.
|
||||
# Professional audio backend for low-latency, high-quality audio routing.
|
||||
jackaudio-backend = ["librespot-playback/jackaudio-backend"]
|
||||
|
||||
# Network discovery backends - choose one for Spotify Connect device discovery
|
||||
# See COMPILING.md for dependencies and platform support.
|
||||
|
||||
# with-libmdns: Pure-Rust mDNS implementation (default).
|
||||
# No external dependencies, works on all platforms. Choose this for simple deployments or when
|
||||
# avoiding system dependencies.
|
||||
with-libmdns = ["librespot-discovery/with-libmdns"]
|
||||
|
||||
# with-avahi: Uses Avahi daemon for mDNS (Linux only).
|
||||
# Integrates with system's Avahi service for network discovery. Choose this when you want to
|
||||
# integrate with existing Avahi infrastructure or need advanced mDNS features. Requires
|
||||
# libavahi-client-dev.
|
||||
with-avahi = ["librespot-discovery/with-avahi"]
|
||||
|
||||
# with-dns-sd: Uses DNS Service Discovery (cross-platform).
|
||||
# On macOS uses Bonjour, on Linux uses Avahi compatibility layer. Choose this for tight system
|
||||
# integration on macOS or when using Avahi's dns-sd compatibility mode on Linux.
|
||||
with-dns-sd = ["librespot-discovery/with-dns-sd"]
|
||||
|
||||
# Audio processing features:
|
||||
|
||||
# passthrough-decoder: Enables direct passthrough of Ogg Vorbis streams without decoding.
|
||||
# Useful for custom audio processing pipelines or when you want to handle audio decoding
|
||||
# externally. When enabled, audio is not decoded by librespot but passed through as raw Ogg Vorbis
|
||||
# data.
|
||||
passthrough-decoder = ["librespot-playback/passthrough-decoder"]
|
||||
|
||||
[lib]
|
||||
name = "librespot"
|
||||
|
@ -21,40 +128,26 @@ name = "librespot"
|
|||
path = "src/main.rs"
|
||||
doc = false
|
||||
|
||||
[dependencies.librespot-audio]
|
||||
path = "audio"
|
||||
version = "0.6.0-dev"
|
||||
|
||||
[dependencies.librespot-connect]
|
||||
path = "connect"
|
||||
version = "0.6.0-dev"
|
||||
|
||||
[dependencies.librespot-core]
|
||||
path = "core"
|
||||
version = "0.6.0-dev"
|
||||
|
||||
[dependencies.librespot-discovery]
|
||||
path = "discovery"
|
||||
version = "0.6.0-dev"
|
||||
default-features = false
|
||||
|
||||
[dependencies.librespot-metadata]
|
||||
path = "metadata"
|
||||
version = "0.6.0-dev"
|
||||
|
||||
[dependencies.librespot-playback]
|
||||
path = "playback"
|
||||
version = "0.6.0-dev"
|
||||
|
||||
[dependencies.librespot-protocol]
|
||||
path = "protocol"
|
||||
version = "0.6.0-dev"
|
||||
|
||||
[dependencies.librespot-oauth]
|
||||
path = "oauth"
|
||||
version = "0.6.0-dev"
|
||||
[workspace.dependencies]
|
||||
librespot-audio = { path = "audio", default-features = false }
|
||||
librespot-connect = { path = "connect", default-features = false }
|
||||
librespot-core = { path = "core", default-features = false }
|
||||
librespot-discovery = { path = "discovery", default-features = false }
|
||||
librespot-metadata = { path = "metadata", default-features = false }
|
||||
librespot-oauth = { path = "oauth", default-features = false }
|
||||
librespot-playback = { path = "playback", default-features = false }
|
||||
librespot-protocol = { path = "protocol", default-features = false }
|
||||
|
||||
[dependencies]
|
||||
librespot-audio.workspace = true
|
||||
librespot-connect.workspace = true
|
||||
librespot-core.workspace = true
|
||||
librespot-discovery.workspace = true
|
||||
librespot-metadata.workspace = true
|
||||
librespot-oauth.workspace = true
|
||||
librespot-playback.workspace = true
|
||||
librespot-protocol.workspace = true
|
||||
|
||||
data-encoding = "2.5"
|
||||
env_logger = { version = "0.11.2", default-features = false, features = [
|
||||
"color",
|
||||
|
@ -77,53 +170,30 @@ tokio = { version = "1", features = [
|
|||
] }
|
||||
url = "2.2"
|
||||
|
||||
[features]
|
||||
alsa-backend = ["librespot-playback/alsa-backend"]
|
||||
portaudio-backend = ["librespot-playback/portaudio-backend"]
|
||||
pulseaudio-backend = ["librespot-playback/pulseaudio-backend"]
|
||||
jackaudio-backend = ["librespot-playback/jackaudio-backend"]
|
||||
rodio-backend = ["librespot-playback/rodio-backend"]
|
||||
rodiojack-backend = ["librespot-playback/rodiojack-backend"]
|
||||
sdl-backend = ["librespot-playback/sdl-backend"]
|
||||
gstreamer-backend = ["librespot-playback/gstreamer-backend"]
|
||||
|
||||
with-avahi = ["librespot-discovery/with-avahi"]
|
||||
with-dns-sd = ["librespot-discovery/with-dns-sd"]
|
||||
with-libmdns = ["librespot-discovery/with-libmdns"]
|
||||
|
||||
passthrough-decoder = ["librespot-playback/passthrough-decoder"]
|
||||
|
||||
default = ["rodio-backend", "with-libmdns"]
|
||||
|
||||
[package.metadata.deb]
|
||||
maintainer = "librespot-org"
|
||||
copyright = "2018 Paul Liétar"
|
||||
maintainer = "Librespot Organization <noreply@github.com>"
|
||||
copyright = "2015, Paul Liétar"
|
||||
license-file = ["LICENSE", "4"]
|
||||
depends = "$auto"
|
||||
recommends = "avahi-daemon"
|
||||
extended-description = """\
|
||||
librespot is an open source client library for Spotify. It enables applications \
|
||||
to use Spotify's service, without using the official but closed-source \
|
||||
libspotify. Additionally, it will provide extra features which are not \
|
||||
available in the official library."""
|
||||
to use Spotify's service to control and play music via various backends, and to \
|
||||
act as a Spotify Connect receiver. It is an alternative to the official and now \
|
||||
deprecated closed-source libspotify. Additionally, it provides extra features \
|
||||
which are not available in the official library.
|
||||
.
|
||||
This package provides the librespot binary for headless Spotify Connect playback. \
|
||||
.
|
||||
Note: librespot only works with Spotify Premium accounts."""
|
||||
section = "sound"
|
||||
priority = "optional"
|
||||
assets = [
|
||||
[
|
||||
"target/release/librespot",
|
||||
"usr/bin/",
|
||||
"755",
|
||||
],
|
||||
[
|
||||
"contrib/librespot.service",
|
||||
"lib/systemd/system/",
|
||||
"644",
|
||||
],
|
||||
[
|
||||
"contrib/librespot.user.service",
|
||||
"lib/systemd/user/",
|
||||
"644",
|
||||
],
|
||||
# Main binary
|
||||
["target/release/librespot", "usr/bin/", "755"],
|
||||
# Documentation
|
||||
["README.md", "usr/share/doc/librespot/", "644"],
|
||||
# Systemd services
|
||||
["contrib/librespot.service", "lib/systemd/system/", "644"],
|
||||
["contrib/librespot.user.service", "lib/systemd/user/", "644"],
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
rust-version = "1.85"
|
||||
|
|
12
Cross.toml
Normal file
12
Cross.toml
Normal file
|
@ -0,0 +1,12 @@
|
|||
[build]
|
||||
pre-build = [
|
||||
"dpkg --add-architecture $CROSS_DEB_ARCH",
|
||||
"apt-get update",
|
||||
"apt-get --assume-yes install libssl-dev:$CROSS_DEB_ARCH libasound2-dev:$CROSS_DEB_ARCH",
|
||||
]
|
||||
|
||||
[target.riscv64gc-unknown-linux-gnu]
|
||||
# RISC-V: Uses rustls-tls (no system dependencies needed)
|
||||
# Building with --no-default-features --features rustls-tls
|
||||
# No pre-build steps required - rustls is pure Rust
|
||||
pre-build = []
|
10
README.md
10
README.md
|
@ -1,4 +1,4 @@
|
|||
[](https://github.com/librespot-org/librespot/actions)
|
||||
[](https://github.com/librespot-org/librespot/actions)
|
||||
[](https://gitter.im/librespot-org/spotify-connect-resources)
|
||||
[](https://crates.io/crates/librespot)
|
||||
|
||||
|
@ -62,13 +62,15 @@ SDL
|
|||
Pipe
|
||||
Subprocess
|
||||
```
|
||||
Please check the corresponding [Compiling](https://github.com/librespot-org/librespot/wiki/Compiling#general-dependencies) entry on the wiki for backend specific dependencies.
|
||||
Please check [COMPILING.md](COMPILING.md) for detailed information on TLS, audio, and discovery backend dependencies, or the [Compiling](https://github.com/librespot-org/librespot/wiki/Compiling#general-dependencies) entry on the wiki for additional backend specific dependencies.
|
||||
|
||||
Once you've installed the dependencies and cloned this repository you can build *librespot* with the default backend using Cargo.
|
||||
Once you've installed the dependencies and cloned this repository you can build *librespot* with the default features using Cargo.
|
||||
```shell
|
||||
cargo build --release
|
||||
```
|
||||
|
||||
By default, this builds with native-tls (system TLS), rodio audio backend, and libmdns discovery. See [COMPILING.md](COMPILING.md) for information on selecting different TLS, audio, and discovery backends.
|
||||
|
||||
# Packages
|
||||
|
||||
librespot is also available via official package system on various operating systems such as Linux, FreeBSD, NetBSD. [Repology](https://repology.org/project/librespot/versions) offers a good overview.
|
||||
|
@ -115,6 +117,6 @@ This is a non exhaustive list of projects that either use or have modified libre
|
|||
- [librespot-java](https://github.com/devgianlu/librespot-java) - A Java port of librespot.
|
||||
- [ncspot](https://github.com/hrkfdn/ncspot) - Cross-platform ncurses Spotify client.
|
||||
- [ansible-role-librespot](https://github.com/xMordax/ansible-role-librespot/tree/master) - Ansible role that will build, install and configure Librespot.
|
||||
- [Spot](https://github.com/xou816/spot) - Gtk/Rust native Spotify client for the GNOME desktop.
|
||||
- [Spot](https://github.com/xou816/spot) - Gtk/Rust native Spotify client for the GNOME desktop.
|
||||
- [Snapcast](https://github.com/badaix/snapcast) - synchronised multi-room audio player that uses librespot as its source for Spotify content
|
||||
- [MuPiBox](https://mupibox.de/) - Portable music box for Spotify and local media based on Raspberry Pi. Operated via touchscreen. Suitable for children and older people.
|
||||
|
|
|
@ -1,25 +1,31 @@
|
|||
[package]
|
||||
name = "librespot-audio"
|
||||
version = "0.6.0-dev"
|
||||
version.workspace = true
|
||||
rust-version.workspace = true
|
||||
authors = ["Paul Lietar <paul@lietar.net>"]
|
||||
license.workspace = true
|
||||
description = "The audio fetching logic for librespot"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/librespot-org/librespot"
|
||||
edition = "2021"
|
||||
repository.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[dependencies.librespot-core]
|
||||
path = "../core"
|
||||
version = "0.6.0-dev"
|
||||
[features]
|
||||
# Refer to the workspace Cargo.toml for the list of features
|
||||
default = ["native-tls"]
|
||||
|
||||
# TLS backend propagation
|
||||
native-tls = ["librespot-core/native-tls"]
|
||||
rustls-tls = ["librespot-core/rustls-tls"]
|
||||
|
||||
[dependencies]
|
||||
librespot-core.workspace = true
|
||||
|
||||
aes = "0.8"
|
||||
bytes = "1"
|
||||
ctr = "0.9"
|
||||
futures-util = "0.3"
|
||||
hyper = "1.6"
|
||||
hyper-util = { version = "0.1", features = ["client"] }
|
||||
http-body-util = "0.1"
|
||||
hyper = { version = "1.6", features = ["http1", "http2"] }
|
||||
hyper-util = { version = "0.1", features = ["client", "http2"] }
|
||||
log = "0.4"
|
||||
parking_lot = { version = "0.12", features = ["deadlock_detection"] }
|
||||
tempfile = "3"
|
||||
|
|
|
@ -162,7 +162,7 @@ impl StreamLoaderController {
|
|||
}
|
||||
|
||||
pub fn range_available(&self, range: Range) -> bool {
|
||||
let available = if let Some(ref shared) = self.stream_shared {
|
||||
if let Some(ref shared) = self.stream_shared {
|
||||
let download_status = shared.download_status.lock();
|
||||
|
||||
range.length
|
||||
|
@ -171,9 +171,7 @@ impl StreamLoaderController {
|
|||
.contained_length_from_value(range.start)
|
||||
} else {
|
||||
range.length <= self.len() - range.start
|
||||
};
|
||||
|
||||
available
|
||||
}
|
||||
}
|
||||
|
||||
pub fn range_to_end_available(&self) -> bool {
|
||||
|
@ -397,12 +395,12 @@ impl AudioFile {
|
|||
|
||||
pub fn get_stream_loader_controller(&self) -> Result<StreamLoaderController, Error> {
|
||||
let controller = match self {
|
||||
AudioFile::Streaming(ref stream) => StreamLoaderController {
|
||||
AudioFile::Streaming(stream) => StreamLoaderController {
|
||||
channel_tx: Some(stream.stream_loader_command_tx.clone()),
|
||||
stream_shared: Some(stream.shared.clone()),
|
||||
file_size: stream.shared.file_size,
|
||||
},
|
||||
AudioFile::Cached(ref file) => StreamLoaderController {
|
||||
AudioFile::Cached(file) => StreamLoaderController {
|
||||
channel_tx: None,
|
||||
stream_shared: None,
|
||||
file_size: file.metadata()?.len() as usize,
|
||||
|
|
|
@ -1,14 +1,26 @@
|
|||
[package]
|
||||
name = "librespot-connect"
|
||||
version = "0.6.0-dev"
|
||||
version.workspace = true
|
||||
rust-version.workspace = true
|
||||
authors = ["Paul Lietar <paul@lietar.net>"]
|
||||
description = "The discovery and Spotify Connect logic for librespot"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/librespot-org/librespot"
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
description = "The Spotify Connect logic for librespot"
|
||||
repository.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[features]
|
||||
# Refer to the workspace Cargo.toml for the list of features
|
||||
default = ["native-tls"]
|
||||
|
||||
# TLS backend propagation
|
||||
native-tls = ["librespot-core/native-tls", "librespot-playback/native-tls"]
|
||||
rustls-tls = ["librespot-core/rustls-tls", "librespot-playback/rustls-tls"]
|
||||
|
||||
[dependencies]
|
||||
librespot-core.workspace = true
|
||||
librespot-playback.workspace = true
|
||||
librespot-protocol.workspace = true
|
||||
|
||||
futures-util = "0.3"
|
||||
log = "0.4"
|
||||
protobuf = "3.7"
|
||||
|
@ -18,15 +30,3 @@ thiserror = "2"
|
|||
tokio = { version = "1", features = ["macros", "parking_lot", "sync"] }
|
||||
tokio-stream = "0.1"
|
||||
uuid = { version = "1.18", features = ["v4"] }
|
||||
|
||||
[dependencies.librespot-core]
|
||||
path = "../core"
|
||||
version = "0.6.0-dev"
|
||||
|
||||
[dependencies.librespot-playback]
|
||||
path = "../playback"
|
||||
version = "0.6.0-dev"
|
||||
|
||||
[dependencies.librespot-protocol]
|
||||
path = "../protocol"
|
||||
version = "0.6.0-dev"
|
||||
|
|
|
@ -1,27 +1,43 @@
|
|||
[package]
|
||||
name = "librespot-core"
|
||||
version = "0.6.0-dev"
|
||||
version.workspace = true
|
||||
rust-version.workspace = true
|
||||
authors = ["Paul Lietar <paul@lietar.net>"]
|
||||
build = "build.rs"
|
||||
license.workspace = true
|
||||
description = "The core functionality provided by librespot"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/librespot-org/librespot"
|
||||
edition = "2021"
|
||||
repository.workspace = true
|
||||
edition.workspace = true
|
||||
build = "build.rs"
|
||||
|
||||
[dependencies.librespot-oauth]
|
||||
path = "../oauth"
|
||||
version = "0.6.0-dev"
|
||||
[features]
|
||||
# Refer to the workspace Cargo.toml for the list of features
|
||||
default = ["native-tls"]
|
||||
|
||||
[dependencies.librespot-protocol]
|
||||
path = "../protocol"
|
||||
version = "0.6.0-dev"
|
||||
# TLS backends (mutually exclusive - see oauth/src/lib.rs for compile-time checks)
|
||||
# Note: Validation is in oauth since it's compiled first in the dependency tree.
|
||||
native-tls = [
|
||||
"dep:hyper-tls",
|
||||
"hyper-proxy2/tls",
|
||||
"librespot-oauth/native-tls",
|
||||
"tokio-tungstenite/native-tls",
|
||||
]
|
||||
rustls-tls = [
|
||||
"dep:hyper-rustls",
|
||||
"hyper-proxy2/rustls",
|
||||
"librespot-oauth/rustls-tls",
|
||||
"tokio-tungstenite/__rustls-tls",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
librespot-oauth.workspace = true
|
||||
librespot-protocol.workspace = true
|
||||
|
||||
aes = "0.8"
|
||||
base64 = "0.22"
|
||||
byteorder = "1.5"
|
||||
bytes = "1"
|
||||
data-encoding = "2.9"
|
||||
flate2 = "1.1"
|
||||
form_urlencoded = "1.2"
|
||||
futures-core = "0.3"
|
||||
futures-util = { version = "0.3", features = [
|
||||
|
@ -37,9 +53,22 @@ governor = { version = "0.10", default-features = false, features = [
|
|||
hmac = "0.12"
|
||||
httparse = "1.10"
|
||||
http = "1.3"
|
||||
hyper = { version = "1.6", features = ["http1", "http2"] }
|
||||
hyper-util = { version = "0.1", features = ["client"] }
|
||||
http-body-util = "0.1"
|
||||
hyper = { version = "1.6", features = ["http1", "http2"] }
|
||||
hyper-proxy2 = { version = "0.1", default-features = false }
|
||||
hyper-rustls = { version = "0.27", default-features = false, features = [
|
||||
"http1",
|
||||
"http2",
|
||||
"ring",
|
||||
"rustls-platform-verifier",
|
||||
"tls12",
|
||||
], optional = true }
|
||||
hyper-tls = { version = "0.6", optional = true }
|
||||
hyper-util = { version = "0.1", default-features = false, features = [
|
||||
"client",
|
||||
"http1",
|
||||
"http2",
|
||||
] }
|
||||
log = "0.4"
|
||||
nonzero_ext = "0.3"
|
||||
num-bigint = "0.4"
|
||||
|
@ -51,6 +80,7 @@ pbkdf2 = { version = "0.12", default-features = false, features = ["hmac"] }
|
|||
pin-project-lite = "0.2"
|
||||
priority-queue = "2.5"
|
||||
protobuf = "3.7"
|
||||
protobuf-json-mapping = "3.7"
|
||||
quick-xml = { version = "0.38", features = ["serialize"] }
|
||||
rand = "0.9"
|
||||
rsa = "0.9"
|
||||
|
@ -71,28 +101,10 @@ tokio = { version = "1", features = [
|
|||
"time",
|
||||
] }
|
||||
tokio-stream = "0.1"
|
||||
tokio-tungstenite = { version = "0.27", default-features = false }
|
||||
tokio-util = { version = "0.7", features = ["codec"] }
|
||||
url = "2"
|
||||
uuid = { version = "1", default-features = false, features = ["v4"] }
|
||||
data-encoding = "2.9"
|
||||
flate2 = "1.1"
|
||||
protobuf-json-mapping = "3.7"
|
||||
rustls = { version = "0.23", default-features = false, features = ["ring"] }
|
||||
|
||||
hyper-proxy2 = { version = "0.1", default-features = false, features = [
|
||||
"rustls-webpki",
|
||||
] }
|
||||
hyper-rustls = { version = "0.27", default-features = false, features = [
|
||||
"ring",
|
||||
"http1",
|
||||
"logging",
|
||||
"tls12",
|
||||
"webpki-tokio",
|
||||
"http2",
|
||||
] }
|
||||
tokio-tungstenite = { version = "0.27", default-features = false, features = [
|
||||
"rustls-tls-webpki-roots",
|
||||
] }
|
||||
|
||||
[build-dependencies]
|
||||
rand = "0.9"
|
||||
|
|
|
@ -13,7 +13,6 @@ use http::{Uri, header::HeaderValue};
|
|||
use http_body_util::{BodyExt, Full};
|
||||
use hyper::{HeaderMap, Request, Response, StatusCode, body::Incoming, header::USER_AGENT};
|
||||
use hyper_proxy2::{Intercept, Proxy, ProxyConnector};
|
||||
use hyper_rustls::{HttpsConnector, HttpsConnectorBuilder};
|
||||
use hyper_util::{
|
||||
client::legacy::{Client, ResponseFuture, connect::HttpConnector},
|
||||
rt::TokioExecutor,
|
||||
|
@ -23,6 +22,11 @@ use parking_lot::Mutex;
|
|||
use thiserror::Error;
|
||||
use url::Url;
|
||||
|
||||
#[cfg(all(feature = "rustls-tls", not(feature = "native-tls")))]
|
||||
use hyper_rustls::{HttpsConnector, HttpsConnectorBuilder};
|
||||
#[cfg(all(feature = "native-tls", not(feature = "rustls-tls")))]
|
||||
use hyper_tls::HttpsConnector;
|
||||
|
||||
use crate::{
|
||||
Error,
|
||||
config::{OS, os_version},
|
||||
|
@ -145,14 +149,15 @@ impl HttpClient {
|
|||
|
||||
fn try_create_hyper_client(proxy_url: Option<&Url>) -> Result<HyperClient, Error> {
|
||||
// configuring TLS is expensive and should be done once per process
|
||||
let _ = rustls::crypto::ring::default_provider()
|
||||
.install_default()
|
||||
.map_err(|e| {
|
||||
Error::internal(format!("unable to install default crypto provider: {e:?}"))
|
||||
});
|
||||
|
||||
let tls = HttpsConnectorBuilder::new().with_webpki_roots();
|
||||
let https_connector = tls.https_or_http().enable_http1().enable_http2().build();
|
||||
#[cfg(all(feature = "rustls-tls", not(feature = "native-tls")))]
|
||||
let https_connector = {
|
||||
let tls = HttpsConnectorBuilder::new().with_platform_verifier();
|
||||
tls.https_or_http().enable_http1().enable_http2().build()
|
||||
};
|
||||
|
||||
#[cfg(all(feature = "native-tls", not(feature = "rustls-tls")))]
|
||||
let https_connector = HttpsConnector::new();
|
||||
|
||||
// When not using a proxy a dummy proxy is configured that will not intercept any traffic.
|
||||
// This prevents needing to carry the Client Connector generics through the whole project
|
||||
|
|
|
@ -1,14 +1,29 @@
|
|||
[package]
|
||||
name = "librespot-discovery"
|
||||
version = "0.6.0-dev"
|
||||
version.workspace = true
|
||||
rust-version.workspace = true
|
||||
authors = ["Paul Lietar <paul@lietar.net>"]
|
||||
license.workspace = true
|
||||
description = "The discovery logic for librespot"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/librespot-org/librespot"
|
||||
edition = "2021"
|
||||
repository.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[features]
|
||||
# Refer to the workspace Cargo.toml for the list of features
|
||||
default = ["with-libmdns", "native-tls"]
|
||||
|
||||
# Discovery backends
|
||||
with-avahi = ["dep:serde", "dep:zbus"]
|
||||
with-dns-sd = ["dep:dns-sd"]
|
||||
with-libmdns = ["dep:libmdns"]
|
||||
|
||||
# TLS backend propagation
|
||||
native-tls = ["librespot-core/native-tls"]
|
||||
rustls-tls = ["librespot-core/rustls-tls"]
|
||||
|
||||
[dependencies]
|
||||
librespot-core.workspace = true
|
||||
|
||||
aes = "0.8"
|
||||
base64 = "0.22"
|
||||
bytes = "1"
|
||||
|
@ -18,13 +33,13 @@ form_urlencoded = "1.2"
|
|||
futures-core = "0.3"
|
||||
futures-util = "0.3"
|
||||
hmac = "0.12"
|
||||
http-body-util = "0.1"
|
||||
hyper = { version = "1.6", features = ["http1"] }
|
||||
hyper-util = { version = "0.1", features = [
|
||||
"server-auto",
|
||||
"server-graceful",
|
||||
"service",
|
||||
] }
|
||||
http-body-util = "0.1"
|
||||
libmdns = { version = "0.9", optional = true }
|
||||
log = "0.4"
|
||||
rand = "0.9"
|
||||
|
@ -40,18 +55,7 @@ zbus = { version = "5", default-features = false, features = [
|
|||
"tokio",
|
||||
], optional = true }
|
||||
|
||||
[dependencies.librespot-core]
|
||||
path = "../core"
|
||||
version = "0.6.0-dev"
|
||||
|
||||
[dev-dependencies]
|
||||
futures = "0.3"
|
||||
hex = "0.4"
|
||||
tokio = { version = "1", features = ["macros", "parking_lot", "rt"] }
|
||||
|
||||
[features]
|
||||
with-avahi = ["zbus", "serde"]
|
||||
with-dns-sd = ["dns-sd"]
|
||||
with-libmdns = ["libmdns"]
|
||||
|
||||
default = ["with-libmdns"]
|
||||
|
|
|
@ -16,6 +16,6 @@ async fn main() {
|
|||
.unwrap();
|
||||
|
||||
while let Some(x) = server.next().await {
|
||||
println!("Received {:?}", x);
|
||||
println!("Received {x:?}");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,6 @@ async fn main() {
|
|||
.unwrap();
|
||||
|
||||
while let Some(x) = server.next().await {
|
||||
println!("Received {:?}", x);
|
||||
println!("Received {x:?}");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,27 +1,30 @@
|
|||
[package]
|
||||
name = "librespot-metadata"
|
||||
version = "0.6.0-dev"
|
||||
version.workspace = true
|
||||
rust-version.workspace = true
|
||||
authors = ["Paul Lietar <paul@lietar.net>"]
|
||||
license.workspace = true
|
||||
description = "The metadata logic for librespot"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/librespot-org/librespot"
|
||||
edition = "2021"
|
||||
repository.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[features]
|
||||
# Refer to the workspace Cargo.toml for the list of features
|
||||
default = ["native-tls"]
|
||||
|
||||
# TLS backend propagation
|
||||
native-tls = ["librespot-core/native-tls"]
|
||||
rustls-tls = ["librespot-core/rustls-tls"]
|
||||
|
||||
[dependencies]
|
||||
librespot-core.workspace = true
|
||||
librespot-protocol.workspace = true
|
||||
|
||||
async-trait = "0.1"
|
||||
bytes = "1"
|
||||
log = "0.4"
|
||||
protobuf = "3.7"
|
||||
thiserror = "2"
|
||||
uuid = { version = "1", default-features = false }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
||||
[dependencies.librespot-core]
|
||||
path = "../core"
|
||||
version = "0.6.0-dev"
|
||||
|
||||
[dependencies.librespot-protocol]
|
||||
path = "../protocol"
|
||||
version = "0.6.0-dev"
|
||||
thiserror = "2"
|
||||
uuid = { version = "1", default-features = false }
|
||||
|
|
|
@ -50,7 +50,7 @@ pub trait Metadata: Send + Sized + 'static {
|
|||
async fn get(session: &Session, id: &SpotifyId) -> Result<Self, Error> {
|
||||
let response = Self::request(session, id).await?;
|
||||
let msg = Self::Message::parse_from_bytes(&response)?;
|
||||
trace!("Received metadata: {:#?}", msg);
|
||||
trace!("Received metadata: {msg:#?}");
|
||||
Self::parse(&msg, id)
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ pub trait MercuryRequest {
|
|||
let _ = write!(metrics_uri, "&product={product}");
|
||||
}
|
||||
|
||||
trace!("Requesting {}", metrics_uri);
|
||||
trace!("Requesting {metrics_uri}");
|
||||
|
||||
let request = session.mercury().get(metrics_uri)?;
|
||||
let response = request.await?;
|
||||
|
|
|
@ -1,23 +1,31 @@
|
|||
[package]
|
||||
name = "librespot-oauth"
|
||||
version = "0.6.0-dev"
|
||||
version.workspace = true
|
||||
rust-version.workspace = true
|
||||
authors = ["Nick Steel <nick@nsteel.co.uk>"]
|
||||
license.workspace = true
|
||||
description = "OAuth authorization code flow with PKCE for obtaining a Spotify access token"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/librespot-org/librespot"
|
||||
edition = "2021"
|
||||
repository.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[features]
|
||||
# Refer to the workspace Cargo.toml for the list of features
|
||||
default = ["native-tls"]
|
||||
|
||||
# TLS backends (mutually exclusive - compile-time checks in src/lib.rs)
|
||||
native-tls = ["oauth2/native-tls", "reqwest/native-tls"]
|
||||
rustls-tls = ["oauth2/rustls-tls", "reqwest/rustls-tls"]
|
||||
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
oauth2 = { version = "5.0", features = ["reqwest", "reqwest-blocking"] }
|
||||
reqwest = { version = "0.12", default-features = false, features = [
|
||||
"blocking",
|
||||
"http2",
|
||||
"rustls-tls",
|
||||
"system-proxy",
|
||||
oauth2 = { version = "5.0", default-features = false, features = [
|
||||
"reqwest",
|
||||
"reqwest-blocking",
|
||||
] }
|
||||
open = "5.3"
|
||||
reqwest = { version = "0.12", default-features = false, features = [
|
||||
"system-proxy",
|
||||
] }
|
||||
thiserror = "2"
|
||||
url = "2.5"
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ async fn main() {
|
|||
{
|
||||
Ok(client) => client,
|
||||
Err(err) => {
|
||||
eprintln!("Unable to build an OAuth client: {}", err);
|
||||
eprintln!("Unable to build an OAuth client: {err}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -41,7 +41,7 @@ fn main() {
|
|||
{
|
||||
Ok(client) => client,
|
||||
Err(err) => {
|
||||
eprintln!("Unable to build an OAuth client: {}", err);
|
||||
eprintln!("Unable to build an OAuth client: {err}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -11,23 +11,42 @@
|
|||
//! a spawned http server (mimicking Spotify's client), or manually via stdin. The latter
|
||||
//! is appropriate for headless systems.
|
||||
|
||||
use log::{error, info, trace};
|
||||
use oauth2::basic::BasicTokenType;
|
||||
use oauth2::{
|
||||
AuthUrl, AuthorizationCode, ClientId, CsrfToken, EndpointNotSet, EndpointSet,
|
||||
PkceCodeChallenge, RedirectUrl, Scope, TokenResponse, TokenUrl, basic::BasicClient,
|
||||
};
|
||||
use oauth2::{EmptyExtraTokenFields, PkceCodeVerifier, RefreshToken, StandardTokenResponse};
|
||||
use std::io;
|
||||
use std::sync::mpsc;
|
||||
use std::time::{Duration, Instant};
|
||||
use std::{
|
||||
io::{BufRead, BufReader, Write},
|
||||
io::{self, BufRead, BufReader, Write},
|
||||
net::{SocketAddr, TcpListener},
|
||||
sync::mpsc,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use oauth2::{
|
||||
AuthUrl, AuthorizationCode, ClientId, CsrfToken, EmptyExtraTokenFields, EndpointNotSet,
|
||||
EndpointSet, PkceCodeChallenge, PkceCodeVerifier, RedirectUrl, RefreshToken, Scope,
|
||||
StandardTokenResponse, TokenResponse, TokenUrl, basic::BasicClient, basic::BasicTokenType,
|
||||
};
|
||||
|
||||
use log::{error, info, trace};
|
||||
use thiserror::Error;
|
||||
use url::Url;
|
||||
|
||||
// TLS Feature Validation
|
||||
//
|
||||
// These compile-time checks are placed in the oauth crate rather than core for a specific reason:
|
||||
// oauth is at the bottom of the dependency tree (even librespot-core depends on librespot-oauth),
|
||||
// which means it gets compiled first. This ensures TLS feature conflicts are detected early in
|
||||
// the build process, providing immediate feedback to users rather than failing later during
|
||||
// core compilation.
|
||||
//
|
||||
// The dependency chain is: workspace -> core -> oauth
|
||||
// So oauth's feature validation runs before core's, catching configuration errors quickly.
|
||||
|
||||
#[cfg(all(feature = "native-tls", feature = "rustls-tls"))]
|
||||
compile_error!("Features 'native-tls' and 'rustls-tls' are mutually exclusive. Enable only one.");
|
||||
|
||||
#[cfg(not(any(feature = "native-tls", feature = "rustls-tls")))]
|
||||
compile_error!(
|
||||
"Either feature \"native-tls\" (default) or \"rustls-tls\" must be enabled for this crate."
|
||||
);
|
||||
|
||||
/// Possible errors encountered during the OAuth authentication flow.
|
||||
#[derive(Debug, Error)]
|
||||
pub enum OAuthError {
|
||||
|
|
|
@ -1,26 +1,51 @@
|
|||
[package]
|
||||
name = "librespot-playback"
|
||||
version = "0.6.0-dev"
|
||||
version.workspace = true
|
||||
rust-version.workspace = true
|
||||
authors = ["Sasha Hilton <sashahilton00@gmail.com>"]
|
||||
license.workspace = true
|
||||
description = "The audio playback logic for librespot"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/librespot-org/librespot"
|
||||
edition = "2021"
|
||||
repository.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[dependencies.librespot-audio]
|
||||
path = "../audio"
|
||||
version = "0.6.0-dev"
|
||||
[features]
|
||||
# Refer to the workspace Cargo.toml for the list of features
|
||||
default = ["rodio-backend", "native-tls"]
|
||||
|
||||
[dependencies.librespot-core]
|
||||
path = "../core"
|
||||
version = "0.6.0-dev"
|
||||
# Audio backends
|
||||
alsa-backend = ["dep:alsa"]
|
||||
gstreamer-backend = [
|
||||
"dep:gstreamer",
|
||||
"dep:gstreamer-app",
|
||||
"dep:gstreamer-audio",
|
||||
]
|
||||
jackaudio-backend = ["dep:jack"]
|
||||
portaudio-backend = ["dep:portaudio-rs"]
|
||||
pulseaudio-backend = ["dep:libpulse-binding", "dep:libpulse-simple-binding"]
|
||||
rodio-backend = ["dep:cpal", "dep:rodio"]
|
||||
rodiojack-backend = ["dep:rodio", "cpal/jack"]
|
||||
sdl-backend = ["dep:sdl2"]
|
||||
|
||||
[dependencies.librespot-metadata]
|
||||
path = "../metadata"
|
||||
version = "0.6.0-dev"
|
||||
# Audio processing features
|
||||
passthrough-decoder = ["dep:ogg"]
|
||||
|
||||
# TLS backend propagation
|
||||
native-tls = [
|
||||
"librespot-core/native-tls",
|
||||
"librespot-audio/native-tls",
|
||||
"librespot-metadata/native-tls",
|
||||
]
|
||||
rustls-tls = [
|
||||
"librespot-core/rustls-tls",
|
||||
"librespot-audio/rustls-tls",
|
||||
"librespot-metadata/rustls-tls",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
librespot-audio.workspace = true
|
||||
librespot-core.workspace = true
|
||||
librespot-metadata.workspace = true
|
||||
|
||||
portable-atomic = "1"
|
||||
futures-util = "0.3"
|
||||
log = "0.4"
|
||||
|
@ -37,21 +62,24 @@ zerocopy = { version = "0.8", features = ["derive"] }
|
|||
|
||||
# Backends
|
||||
alsa = { version = "0.9", optional = true }
|
||||
portaudio-rs = { version = "0.3", optional = true }
|
||||
libpulse-binding = { version = "2", optional = true, default-features = false }
|
||||
libpulse-simple-binding = { version = "2", optional = true, default-features = false }
|
||||
jack = { version = "0.13", optional = true }
|
||||
portaudio-rs = { version = "0.3", optional = true }
|
||||
sdl2 = { version = "0.38", optional = true }
|
||||
|
||||
# GStreamer dependencies
|
||||
gstreamer = { version = "0.24", optional = true }
|
||||
gstreamer-app = { version = "0.24", optional = true }
|
||||
gstreamer-audio = { version = "0.24", optional = true }
|
||||
glib = { version = "0.21", optional = true }
|
||||
|
||||
# PulseAudio dependencies
|
||||
libpulse-binding = { version = "2", optional = true, default-features = false }
|
||||
libpulse-simple-binding = { version = "2", optional = true, default-features = false }
|
||||
|
||||
# Rodio dependencies
|
||||
cpal = { version = "0.16", optional = true }
|
||||
rodio = { version = "0.21", optional = true, default-features = false, features = [
|
||||
"playback",
|
||||
] }
|
||||
cpal = { version = "0.16", optional = true }
|
||||
|
||||
# Container and audio decoder
|
||||
symphonia = { version = "0.5", default-features = false, features = [
|
||||
|
@ -66,15 +94,3 @@ ogg = { version = "0.9", optional = true }
|
|||
# Dithering
|
||||
rand = { version = "0.9", features = ["small_rng"] }
|
||||
rand_distr = "0.5"
|
||||
|
||||
[features]
|
||||
alsa-backend = ["alsa"]
|
||||
portaudio-backend = ["portaudio-rs"]
|
||||
pulseaudio-backend = ["libpulse-binding", "libpulse-simple-binding"]
|
||||
jackaudio-backend = ["jack"]
|
||||
rodio-backend = ["rodio", "cpal"]
|
||||
rodiojack-backend = ["rodio", "cpal/jack"]
|
||||
sdl-backend = ["sdl2"]
|
||||
gstreamer-backend = ["gstreamer", "gstreamer-app", "gstreamer-audio"]
|
||||
|
||||
passthrough-decoder = ["ogg"]
|
||||
|
|
|
@ -81,7 +81,7 @@ impl MappedCtrl for VolumeCtrl {
|
|||
|
||||
fn set_db_range(&mut self, new_db_range: f64) {
|
||||
match self {
|
||||
Self::Cubic(ref mut db_range) | Self::Log(ref mut db_range) => *db_range = new_db_range,
|
||||
Self::Cubic(db_range) | Self::Log(db_range) => *db_range = new_db_range,
|
||||
_ => error!("Invalid to set dB range for volume control type {self:?}"),
|
||||
}
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
[package]
|
||||
name = "librespot-protocol"
|
||||
version = "0.6.0-dev"
|
||||
version.workspace = true
|
||||
rust-version.workspace = true
|
||||
authors = ["Paul Liétar <paul@lietar.net>"]
|
||||
build = "build.rs"
|
||||
license.workspace = true
|
||||
description = "The protobuf logic for communicating with Spotify servers"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/librespot-org/librespot"
|
||||
edition = "2021"
|
||||
repository.workspace = true
|
||||
edition.workspace = true
|
||||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
protobuf = "3.7"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue