mirror of
https://github.com/Xevion/spotify-quickauth.git
synced 2025-12-06 11:16:30 -06:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0db9b6a795 | |||
| 3b8e27d9a4 | |||
| 31b5e6ee8b | |||
| 20c863e660 | |||
| 0d0fe8a9e5 | |||
| 3fb288f404 | |||
| 8e33506f61 | |||
| 48b0101dab | |||
| f583dac944 | |||
| dbfad44a51 | |||
| a636c6301a | |||
| 30d135a4dc | |||
| 62fb74a153 | |||
| c3e15fd9a5 | |||
| 0cc92b8978 | |||
| 2e15d81dc9 | |||
| 28faf71583 | |||
| 9ef2aac601 | |||
| 7e7af5920b | |||
| 978b0ab264 | |||
| a4568b2e72 | |||
| 7eaea3e2f4 | |||
| 22606aad30 |
@@ -1,6 +1,3 @@
|
||||
[target.x86_64-unknown-linux-musl]
|
||||
runner = "musl-gcc"
|
||||
|
||||
[profile.release]
|
||||
opt-level = "z"
|
||||
strip = true
|
||||
|
||||
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.hooks/*.sh linguist-vendored
|
||||
51
.github/workflows/build.yaml
vendored
51
.github/workflows/build.yaml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Build
|
||||
name: build
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -7,27 +7,29 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
fail_fast:
|
||||
description: 'Fail fast strategy'
|
||||
description: "Use fail-fast strategy"
|
||||
required: false
|
||||
default: 'true'
|
||||
default: "true"
|
||||
verbose:
|
||||
description: 'Verbose output'
|
||||
description: "Verbose output"
|
||||
required: false
|
||||
default: 'false'
|
||||
default: "false"
|
||||
push:
|
||||
tags:
|
||||
- 'v*.*.*'
|
||||
paths-ignore:
|
||||
- README.md
|
||||
- .gitignore
|
||||
- LICENSE
|
||||
- run.sh
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
# We don't filter by paths here, because we filter by tags, which means we're releasing. All releases should be built.
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- .hooks/**
|
||||
- CARGO_README.md
|
||||
- README.md
|
||||
- CHANGELOG.md
|
||||
- INTEGRATION.md
|
||||
- .gitignore
|
||||
- LICENSE
|
||||
- .gitattributes
|
||||
- LICENSE*
|
||||
- run.sh
|
||||
- run.ps1
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
@@ -36,7 +38,7 @@ jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: ${{ startsWith(github.ref, 'refs/tags/') || github.event.inputs.fail_fast == 'true' }}
|
||||
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
@@ -72,7 +74,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: stable
|
||||
toolchain: 1.79
|
||||
targets: ${{ matrix.target }}
|
||||
|
||||
- name: Cache Rust dependencies
|
||||
@@ -86,7 +88,7 @@ jobs:
|
||||
key: ${{ runner.os }}-${{ matrix.target }}-${{ hashFiles('Cargo.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-${{ matrix.target }}-
|
||||
|
||||
|
||||
- name: Install Linker Tools
|
||||
if: matrix.tools
|
||||
run: |
|
||||
@@ -125,7 +127,7 @@ jobs:
|
||||
echo "ARCHIVE_DIR=$ARCHIVE_DIR" >> $GITHUB_ENV
|
||||
echo "RELEASE_VERSION=$RELEASE_VERSION" >> $GITHUB_ENV
|
||||
echo "ARCHIVE=$ARCHIVE" >> $GITHUB_ENV
|
||||
|
||||
|
||||
- name: Archive
|
||||
if: ${{ !contains(matrix.os, 'windows') }}
|
||||
uses: TheDoctor0/zip-release@0.7.6
|
||||
@@ -145,13 +147,13 @@ jobs:
|
||||
directory: ${{ env.ARCHIVE_DIR }}/
|
||||
path: |
|
||||
spotify-quickauth.exe
|
||||
|
||||
|
||||
- name: Install rsign2
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
uses: taiki-e/install-action@v2
|
||||
with:
|
||||
tool: rsign2
|
||||
|
||||
|
||||
- name: Sign Archive
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
env:
|
||||
@@ -160,13 +162,13 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
echo "$MINISIGN_KEY" > minisign.key
|
||||
|
||||
|
||||
ts=$(node -e 'console.log((new Date).toISOString())')
|
||||
git=$(git rev-parse HEAD)
|
||||
comment="gh=$GITHUB_REPOSITORY git=$git ts=$ts run=$GITHUB_RUN_ID"
|
||||
|
||||
|
||||
rsign sign -W -s minisign.key -x "${{ env.ARCHIVE_PATH }}.sig" -t "$comment" "${{ env.ARCHIVE_PATH }}"
|
||||
|
||||
|
||||
- name: Upload Artifact
|
||||
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
||||
uses: actions/upload-artifact@v4
|
||||
@@ -180,6 +182,7 @@ jobs:
|
||||
uses: softprops/action-gh-release@v2
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
token: ${{ secrets.GH_RELEASE_TOKEN }}
|
||||
files: |
|
||||
${{ env.ARCHIVE_DIR }}/${{ env.ARCHIVE }}
|
||||
${{ env.ARCHIVE_DIR }}/${{ env.ARCHIVE }}.sig
|
||||
@@ -187,7 +190,7 @@ jobs:
|
||||
|
||||
- if: ${{ startsWith(github.ref, 'refs/tags/') && matrix.target == 'x86_64-unknown-linux-musl' }}
|
||||
run: cargo login ${{ secrets.CRATES_IO_API_TOKEN }}
|
||||
|
||||
|
||||
- name: "Publish"
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/') && matrix.target == 'x86_64-unknown-linux-musl' }}
|
||||
run: cargo publish --locked --allow-dirty
|
||||
run: cargo publish --locked --allow-dirty
|
||||
|
||||
2
.github/workflows/integration.yaml
vendored
2
.github/workflows/integration.yaml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Integration
|
||||
name: integration
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
2
.github/workflows/pages.yaml
vendored
2
.github/workflows/pages.yaml
vendored
@@ -1,4 +1,4 @@
|
||||
name: GitHub Pages
|
||||
name: github-pages
|
||||
|
||||
permissions:
|
||||
pages: write
|
||||
|
||||
98
.github/workflows/test.yaml
vendored
Normal file
98
.github/workflows/test.yaml
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
name: test
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths-ignore:
|
||||
- .hooks/**
|
||||
- CARGO_README.md
|
||||
- README.md
|
||||
- CHANGELOG.md
|
||||
- INTEGRATION.md
|
||||
- .gitignore
|
||||
- .gitattributes
|
||||
- LICENSE*
|
||||
- run.sh
|
||||
- run.ps1
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- .hooks/**
|
||||
- CARGO_README.md
|
||||
- README.md
|
||||
- CHANGELOG.md
|
||||
- INTEGRATION.md
|
||||
- .gitignore
|
||||
- .gitattributes
|
||||
- LICENSE*
|
||||
- run.sh
|
||||
- run.ps1
|
||||
schedule:
|
||||
- cron: "30 14 * * 1" # every Monday, 9:30 AM CDT
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: true
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
target: x86_64-unknown-linux-musl
|
||||
tools: musl-tools
|
||||
artifact: true
|
||||
- os: macos-13
|
||||
target: x86_64-apple-darwin
|
||||
# - os: macos-latest
|
||||
# target: aarch64-apple-darwin
|
||||
- os: windows-latest
|
||||
target: x86_64-pc-windows-msvc
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
name: test-${{ matrix.os }}-${{ matrix.target }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: 1.79
|
||||
targets: ${{ matrix.target }}
|
||||
|
||||
- name: Install Linker Tools
|
||||
if: matrix.tools
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install ${{ matrix.tools }}
|
||||
# ensure has a newline at the end
|
||||
[ "$(tail -c 1 .cargo/config.toml)" != "" ] && echo >> .cargo/config.toml
|
||||
cat .cargo/config.github.toml >> .cargo/config.toml
|
||||
|
||||
- name: Cache Rust dependencies
|
||||
uses: actions/cache@v4.0.2
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry/index
|
||||
~/.cargo/registry/cache
|
||||
~/.cargo/git
|
||||
target
|
||||
key: testing-${{ runner.os }}-${{ matrix.target }}-${{ hashFiles('Cargo.lock') }}
|
||||
restore-keys: |
|
||||
testing-${{ runner.os }}-${{ matrix.target }}-
|
||||
testing-${{ runner.os }}-
|
||||
|
||||
- name: Run tests
|
||||
run: cargo test --verbose --target ${{ matrix.target }}
|
||||
|
||||
- name: Build
|
||||
if: matrix.artifact
|
||||
run: cargo build --verbose --target ${{ matrix.target }}
|
||||
|
||||
- name: Upload Artifact
|
||||
if: matrix.artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: spotify-quickauth-${{ github.sha }}-${{ matrix.target }}
|
||||
path: target/${{ matrix.target }}/debug/spotify-quickauth
|
||||
7
.hooks/pre-commit.sh
vendored
7
.hooks/pre-commit.sh
vendored
@@ -1,7 +1,10 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Remove all lines starting with >[! from CARGO_README.md
|
||||
sed -i '/^>\[!/d' CARGO_README.md
|
||||
# TODO: Only run when README.md is modified
|
||||
# TODO: Support partial staging, where the 'Staged' version is copied to CARGO_README.md, and then `sed` is ran.
|
||||
|
||||
# Remove markdown extension lines for Cargo publishing
|
||||
sed '/^>\[!/d' README.md > CARGO_README.md
|
||||
|
||||
# Add the modified file to the commit
|
||||
git add CARGO_README.md
|
||||
@@ -1,8 +1,20 @@
|
||||
> [!IMPORTANT]
|
||||
> This application is not 'real'; I mostly created it to learn about building a CLI application in Rust with high-end CI/CD pipelines and easy to execute multi-platform scripts.
|
||||
> Interestingly enough, I never really developed the program itself, just the scripts and the CI/CD pipeline.
|
||||
> And by the time I was ready to write it, the `spotify-player` project had already solved the [primary issue](https://github.com/aome510/spotify-player/issues/201#issuecomment-2439565162) I was trying to address.
|
||||
> Thus, I'm archiving this project, as it's no longer necessary.
|
||||
>
|
||||
> This project is still pretty cool though in it's own right, with multi-platform ephemeral binaries over `curl` commands, Windows support, Linux MUSL targets (smaller binaries), ARM64 MacOS support, binary deployment to GitHub pages, automatic GitHub release uploads, and a pretty decent README - this project has it all.
|
||||
|
||||
# spotify-quickauth
|
||||
|
||||
[](https://github.com/Xevion/spotify-quickauth/actions)
|
||||
[](https://github.com/Xevion/spotify-quickauth/actions)
|
||||
[](https://github.com/Xevion/spotify-quickauth/actions)
|
||||
[](https://crates.io/crates/spotify-quickauth)
|
||||

|
||||

|
||||
|
||||
<!-- TODO: Add testing status badge -->
|
||||
|
||||
A simple CLI-based application for creating a `credentials.json` file, used by `librespot` derived applications, such as [spotify-player][spotify-player], [spotifyd][spotifyd], and [raspotify][raspotify].
|
||||
|
||||
@@ -10,8 +22,6 @@ A simple CLI-based application for creating a `credentials.json` file, used by `
|
||||
- Automatically places configuration files
|
||||
- No dependencies, no installation, no fuss
|
||||
|
||||
>This README is literally filled with lies. I'm not joking, I've just typed up a bunch of features I plan to implement, and am planning them out now. A fair amount of it works, but most of the specific options aren't currently implemented. I'm working on it, I promise!
|
||||
|
||||
## Quickstart
|
||||
|
||||
You can run this application without installing anything by using the following commands.
|
||||
@@ -22,6 +32,7 @@ curl -sSL https://xevion.github.io/spotify-quickauth/run.sh | sh -s --
|
||||
|
||||
The default invocation is likely fine for most users, it will try to understand the available paths for `credentials.json` to be written to, and allow you to select them.
|
||||
|
||||
> [!NOTE]
|
||||
> Automatic detection is dependent on the related software being installed and/or relevant configuration files being present.
|
||||
|
||||
For **Windows**, you can paste this command into PowerShell:
|
||||
@@ -34,7 +45,8 @@ iex (irm "https://xevion.github.io/spotify-quickauth/run.ps1")
|
||||
|
||||
This application is dead simple to use. Just run the command, and it'll tell you to connect to a fake 'device' in your Spotify interface.
|
||||
|
||||
> You must be connected to the same network running `spotify-quickauth`, as the `zeroconf` technology **does not work** across **networks** nor **proxies**.
|
||||
> [!NOTE]
|
||||
> You must be connected to the same network running `spotify-quickauth`, as the `zeroconf` technology **does not work** across **networks** nor **proxies**.
|
||||
|
||||
Once you connect, the credentials file will be created, and you'll be prompted to select which location(s) to place it in. Even if none of the relevant `librespot` applications are detected or installed, you can specify manual locations, or the current working directory.
|
||||
|
||||
@@ -42,14 +54,15 @@ Once you connect, the credentials file will be created, and you'll be prompted t
|
||||
|
||||
Installation is not necessary to use this application, but if you're having trouble, want to compile it yourself, or are using it frequently, you might want to install it.
|
||||
|
||||
>The scripts above can be given the `-K` or `--keep` flag to keep the downloaded binary. This will prevent repeated API calls to GitHub if you're using the script frequently within a short period.
|
||||
|
||||
> [!NOTE]
|
||||
> The scripts above can be given the `-K` or `--keep` flag to keep the downloaded binary. This will prevent repeated API calls to GitHub if you're using the script frequently within a short period.
|
||||
|
||||
### Pre-built Binaries
|
||||
|
||||
Binaries are always available for download from the [releases page][releases], and they're the same ones used by the shell scripts above.
|
||||
Binaries are always available for download from the [releases page][latestRelease], and they're the same ones used by the shell scripts above.
|
||||
|
||||
Currently, the following targets are available for download:
|
||||
|
||||
- x64 Linux (MUSL) `x86_64-unknown-linux-musl`
|
||||
- ARM64 Linux (MUSL) `aarch64-unknown-linux-musl`
|
||||
- ARMv7 Linux `armv7-unknown-linux-musleabihf`
|
||||
@@ -58,14 +71,33 @@ Currently, the following targets are available for download:
|
||||
- x64 Windows `x86_64-pc-windows-msvc`
|
||||
- ARM64 Windows `aarch64-pc-windows-msvc`
|
||||
|
||||
Please [file an issue][new-issue] if you are on a platform that is not supported, or if you encounter issues with the binaries.
|
||||
|
||||
### Via `cargo-binstall`
|
||||
|
||||
> [!NOTE]
|
||||
> If the package cannot be found for your target or fails to be downloaded for any reason, `cargo-binstall` will automatically fall back to building the package from source.
|
||||
|
||||
`cargo-binstall` is a tool that allows you to install binaries from crates.io without needing to compile them yourself.
|
||||
|
||||
```
|
||||
cargo binstall spotify-quickauth
|
||||
```
|
||||
|
||||
If you're curious where the binary comes from, `cargo-binstall` will likely pull the binary directly from the [latest release][latestRelease] by this repository, selecting the most appropriate target for your host.
|
||||
|
||||
### Manual Installation
|
||||
|
||||
If you'd like to use the shell script above to install the binary, you can use the `-S/--stop` flag to prevent the script from running the binary after downloading it. It implicitly applies the `--keep` flag too.
|
||||
|
||||
You'll need to move the binary yourself though:
|
||||
|
||||
```bash
|
||||
curl -sSL https://xevion.github.io/spotify-quickauth/run.sh | sh -s -- -S
|
||||
mv spotify-quickauth /usr/local/bin
|
||||
```
|
||||
|
||||
Then you can move it to whatever location you'd like. Make sure that directory is in your $PATH though!
|
||||
Make sure your directory of choice is in your $PATH though!
|
||||
|
||||
### Building from Source
|
||||
|
||||
@@ -82,13 +114,17 @@ spotify-quickauth --help
|
||||
```
|
||||
|
||||
If you have any troubles building the project
|
||||
- Make sure you're using a target that's supported by the project (see above).
|
||||
- Certain targets may require specfic linkers. For example,
|
||||
|
||||
- Make sure you're using a target that's supported by the project (see above).
|
||||
- Certain targets may require specfic linkers. For example,
|
||||
|
||||
[latestRelease]: https://github.com/Xevion/spotify-quickauth/releases/latest/
|
||||
[spotify-player]: https://github.com/aome510/spotify-player
|
||||
[spotifyd]: https://github.com/Spotifyd/spotifyd
|
||||
[raspotify]: https://github.com/dtcooper/raspotify
|
||||
[rustup]: https://rustup.rs
|
||||
[git]: https://git-scm.com
|
||||
[binstall]: https://github.com/cargo-bins/cargo-binstall
|
||||
[quickinstall]: https://github.com/cargo-bins/cargo-quickinstall
|
||||
[quickinstall]: https://github.com/cargo-bins/cargo-quickinstall
|
||||
[binstall-installation]: https://github.com/cargo-bins/cargo-binstall#installation
|
||||
[new-issue]: https://github.com/Xevion/spotify-quickauth/issues/new
|
||||
|
||||
37
CHANGELOG.md
Normal file
37
CHANGELOG.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## v0.1.7
|
||||
|
||||
### Added
|
||||
|
||||
- Archival notice.
|
||||
|
||||
### Changed
|
||||
|
||||
- Bumped MSRV to 1.79 to access stabilized `std::path::absolute`
|
||||
- Adjusted `github-linguist` statistics, ignoring `.hooks`
|
||||
- Widened `paths-ignore` for `build` and `test` workflows.
|
||||
- Switched release step token to use `secrets.GH_RELEASE_TOKEN`, so the author is bound to `Xevion` instead of `github-actions` (a bot).
|
||||
- Switched changelog format to `keep-a-changelog` style.
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed `paths-ignore` for `build` workflow on `push` trigger.
|
||||
|
||||
## v0.1.6
|
||||
|
||||
### Added
|
||||
|
||||
- Began tracking changes in the `CHANGELOG.md` file.
|
||||
- Added testing workflow to the repository, targeting only major x64 platforms.
|
||||
- Added testing badge to README
|
||||
|
||||
### Changed
|
||||
|
||||
- [breaking] Lowered MSRV to 1.74 to match `librespot`'s `0.5.0-dev` branch.
|
||||
- Fixed `pre-commit` hook to properly process the `CARGO_README.md` file.
|
||||
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -1287,7 +1287,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "spotify-quickauth"
|
||||
version = "0.1.5"
|
||||
version = "0.1.7"
|
||||
dependencies = [
|
||||
"env_logger",
|
||||
"futures",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
[package]
|
||||
name = "spotify-quickauth"
|
||||
version = "0.1.5"
|
||||
version = "0.1.7"
|
||||
edition = "2021"
|
||||
description = "Quickly authenticate librespot-based applications with Spotify"
|
||||
rust-version = "1.81"
|
||||
rust-version = "1.79"
|
||||
authors = ["Ryan Walters <xevion@xevion.dev>"]
|
||||
homepage = "https://github.com/Xevion/spotify-quickauth"
|
||||
repository = "https://github.com/Xevion/spotify-quickauth"
|
||||
|
||||
37
README.md
37
README.md
@@ -1,12 +1,20 @@
|
||||
> [!IMPORTANT]
|
||||
> This application is not 'real'; I mostly created it to learn about building a CLI application in Rust with high-end CI/CD pipelines and easy to execute multi-platform scripts.
|
||||
> Interestingly enough, I never really developed the program itself, just the scripts and the CI/CD pipeline.
|
||||
> And by the time I was ready to write it, the `spotify-player` project had already solved the [primary issue](https://github.com/aome510/spotify-player/issues/201#issuecomment-2439565162) I was trying to address.
|
||||
> Thus, I'm archiving this project, as it's no longer necessary.
|
||||
>
|
||||
> This project is still pretty cool though in it's own right, with multi-platform ephemeral binaries over `curl` commands, Windows support, Linux MUSL targets (smaller binaries), ARM64 MacOS support, binary deployment to GitHub pages, automatic GitHub release uploads, and a pretty decent README - this project has it all.
|
||||
|
||||
# spotify-quickauth
|
||||
|
||||
[](https://github.com/Xevion/spotify-quickauth/actions)
|
||||
<!-- TODO: Add testing status badge -->
|
||||
[](https://github.com/Xevion/spotify-quickauth/actions)
|
||||
[](https://github.com/Xevion/spotify-quickauth/actions)
|
||||
[](https://crates.io/crates/spotify-quickauth)
|
||||

|
||||

|
||||
|
||||
|
||||
<!-- TODO: Add testing status badge -->
|
||||
|
||||
A simple CLI-based application for creating a `credentials.json` file, used by `librespot` derived applications, such as [spotify-player][spotify-player], [spotifyd][spotifyd], and [raspotify][raspotify].
|
||||
|
||||
@@ -14,9 +22,6 @@ A simple CLI-based application for creating a `credentials.json` file, used by `
|
||||
- Automatically places configuration files
|
||||
- No dependencies, no installation, no fuss
|
||||
|
||||
>[!WARNING]
|
||||
>This README is literally filled with lies. I'm not joking, I've just typed up a bunch of features I plan to implement, and am planning them out now. A fair amount of it works, but most of the specific options aren't currently implemented. I'm working on it, I promise!
|
||||
|
||||
## Quickstart
|
||||
|
||||
You can run this application without installing anything by using the following commands.
|
||||
@@ -27,7 +32,7 @@ curl -sSL https://xevion.github.io/spotify-quickauth/run.sh | sh -s --
|
||||
|
||||
The default invocation is likely fine for most users, it will try to understand the available paths for `credentials.json` to be written to, and allow you to select them.
|
||||
|
||||
>[!NOTE]
|
||||
> [!NOTE]
|
||||
> Automatic detection is dependent on the related software being installed and/or relevant configuration files being present.
|
||||
|
||||
For **Windows**, you can paste this command into PowerShell:
|
||||
@@ -40,8 +45,8 @@ iex (irm "https://xevion.github.io/spotify-quickauth/run.ps1")
|
||||
|
||||
This application is dead simple to use. Just run the command, and it'll tell you to connect to a fake 'device' in your Spotify interface.
|
||||
|
||||
>[!NOTE]
|
||||
> You must be connected to the same network running `spotify-quickauth`, as the `zeroconf` technology **does not work** across **networks** nor **proxies**.
|
||||
> [!NOTE]
|
||||
> You must be connected to the same network running `spotify-quickauth`, as the `zeroconf` technology **does not work** across **networks** nor **proxies**.
|
||||
|
||||
Once you connect, the credentials file will be created, and you'll be prompted to select which location(s) to place it in. Even if none of the relevant `librespot` applications are detected or installed, you can specify manual locations, or the current working directory.
|
||||
|
||||
@@ -49,15 +54,15 @@ Once you connect, the credentials file will be created, and you'll be prompted t
|
||||
|
||||
Installation is not necessary to use this application, but if you're having trouble, want to compile it yourself, or are using it frequently, you might want to install it.
|
||||
|
||||
>[!NOTE]
|
||||
>The scripts above can be given the `-K` or `--keep` flag to keep the downloaded binary. This will prevent repeated API calls to GitHub if you're using the script frequently within a short period.
|
||||
|
||||
> [!NOTE]
|
||||
> The scripts above can be given the `-K` or `--keep` flag to keep the downloaded binary. This will prevent repeated API calls to GitHub if you're using the script frequently within a short period.
|
||||
|
||||
### Pre-built Binaries
|
||||
|
||||
Binaries are always available for download from the [releases page][latestRelease], and they're the same ones used by the shell scripts above.
|
||||
|
||||
Currently, the following targets are available for download:
|
||||
|
||||
- x64 Linux (MUSL) `x86_64-unknown-linux-musl`
|
||||
- ARM64 Linux (MUSL) `aarch64-unknown-linux-musl`
|
||||
- ARMv7 Linux `armv7-unknown-linux-musleabihf`
|
||||
@@ -70,7 +75,7 @@ Please [file an issue][new-issue] if you are on a platform that is not supported
|
||||
|
||||
### Via `cargo-binstall`
|
||||
|
||||
>[!NOTE]
|
||||
> [!NOTE]
|
||||
> If the package cannot be found for your target or fails to be downloaded for any reason, `cargo-binstall` will automatically fall back to building the package from source.
|
||||
|
||||
`cargo-binstall` is a tool that allows you to install binaries from crates.io without needing to compile them yourself.
|
||||
@@ -81,7 +86,6 @@ cargo binstall spotify-quickauth
|
||||
|
||||
If you're curious where the binary comes from, `cargo-binstall` will likely pull the binary directly from the [latest release][latestRelease] by this repository, selecting the most appropriate target for your host.
|
||||
|
||||
|
||||
### Manual Installation
|
||||
|
||||
If you'd like to use the shell script above to install the binary, you can use the `-S/--stop` flag to prevent the script from running the binary after downloading it. It implicitly applies the `--keep` flag too.
|
||||
@@ -110,8 +114,9 @@ spotify-quickauth --help
|
||||
```
|
||||
|
||||
If you have any troubles building the project
|
||||
|
||||
- Make sure you're using a target that's supported by the project (see above).
|
||||
- Certain targets may require specfic linkers. For example,
|
||||
- Certain targets may require specfic linkers. For example,
|
||||
|
||||
[latestRelease]: https://github.com/Xevion/spotify-quickauth/releases/latest/
|
||||
[spotify-player]: https://github.com/aome510/spotify-player
|
||||
@@ -122,4 +127,4 @@ If you have any troubles building the project
|
||||
[binstall]: https://github.com/cargo-bins/cargo-binstall
|
||||
[quickinstall]: https://github.com/cargo-bins/cargo-quickinstall
|
||||
[binstall-installation]: https://github.com/cargo-bins/cargo-binstall#installation
|
||||
[new-issue]: https://github.com/Xevion/spotify-quickauth/issues/new
|
||||
[new-issue]: https://github.com/Xevion/spotify-quickauth/issues/new
|
||||
|
||||
195
src/main.rs
195
src/main.rs
@@ -1,42 +1,174 @@
|
||||
use std::{env, fs::File, process::exit};
|
||||
use std::{env, fs::File, path::PathBuf, process::exit};
|
||||
|
||||
use futures::StreamExt;
|
||||
use librespot_core::config::DeviceType;
|
||||
use librespot_discovery::Discovery;
|
||||
use log::{info, warn};
|
||||
use log::{debug, error, info, warn};
|
||||
use sha1::{Digest, Sha1};
|
||||
use std::io::Write;
|
||||
|
||||
struct Arguments {
|
||||
force: bool,
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
fn parse_arguments(args: &Vec<String>) -> Result<Arguments, String> {
|
||||
let mut force: Option<bool> = None;
|
||||
let mut path: Option<PathBuf> = None;
|
||||
|
||||
let mut skip = 1;
|
||||
// If '--' is provided, all arguments before it are skipped
|
||||
if let Some(index) = args.iter().position(|arg| arg == "--") {
|
||||
skip = index + 1;
|
||||
}
|
||||
|
||||
let args = &args[skip..];
|
||||
debug!("Arguments: {:?}", args);
|
||||
|
||||
for arg in args.iter() {
|
||||
match arg.as_str() {
|
||||
"-f" | "--force" => {
|
||||
if force.is_some() {
|
||||
return Err("Force flag provided multiple times".to_string());
|
||||
}
|
||||
force = Some(true)
|
||||
}
|
||||
_ => {
|
||||
if path.is_some() {
|
||||
return Err("Path provided multiple times".to_string());
|
||||
}
|
||||
|
||||
// Parse the path, validate that the argument looks like a path
|
||||
let parsed = PathBuf::from(arg);
|
||||
debug!("Parsed path: {}", parsed.display());
|
||||
|
||||
if parsed.exists() {
|
||||
if parsed.is_dir() {
|
||||
path = Some(parsed.join("credentials.json"));
|
||||
} else if parsed.is_file() {
|
||||
if path.is_some() {
|
||||
return Err("Path provided multiple times".to_string());
|
||||
}
|
||||
path = Some(parsed);
|
||||
} else {
|
||||
return Err("Path is not a file or directory".to_string());
|
||||
}
|
||||
} else {
|
||||
// File does not exist, check if it looks like a directory
|
||||
if parsed.ends_with("/") || parsed.ends_with("\\") {
|
||||
// If the parent directory exists, it's okay to create a directory then the file in it
|
||||
if parsed.parent().is_some_and(|p| p.exists()) {
|
||||
path = Some(parsed.join("credentials.json"));
|
||||
} else {
|
||||
return Err(
|
||||
"Cannot create more than one folder for output path".to_string()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// No need to create a directory, just create the file
|
||||
if parsed.parent().is_some_and(|p| p.exists()) {
|
||||
path = Some(parsed);
|
||||
} else {
|
||||
return Err(
|
||||
"Cannot create a file in a non-existent directory".to_string()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no path was provided, default to credentials.json in the current directory
|
||||
let path = match path {
|
||||
Some(p) => match std::path::absolute(p) {
|
||||
Ok(p) => p,
|
||||
Err(e) => return Err(format!("Invalid path: {}", e)),
|
||||
},
|
||||
None => {
|
||||
// No path provided, try to identify a default in the current directory
|
||||
let pwd = env::current_dir();
|
||||
if pwd.is_err() {
|
||||
// For some reason the current directory
|
||||
return Err("Current directory is invalid or indeterminate, please provide an explicit output path".to_string());
|
||||
}
|
||||
|
||||
// Default to credentials.json in the current directory
|
||||
pwd.unwrap().join("credentials.json")
|
||||
}
|
||||
};
|
||||
|
||||
// If the *file* already exists, check if the force flag was provided
|
||||
if path.exists() && path.is_file() && !force.unwrap_or(false) {
|
||||
return Err(format!(
|
||||
"Output file already exists, use -f to overwrite ({})",
|
||||
path.display()
|
||||
));
|
||||
}
|
||||
|
||||
Ok(Arguments {
|
||||
force: force.unwrap_or(false),
|
||||
path,
|
||||
})
|
||||
}
|
||||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn main() {
|
||||
async fn main() {
|
||||
// Initialize the logger
|
||||
if env::var("RUST_LOG").is_err() {
|
||||
env::set_var("RUST_LOG", "info")
|
||||
}
|
||||
env_logger::builder().init();
|
||||
|
||||
let credentials_file = match home::home_dir() {
|
||||
// ~/.cache/spotify_player/credentials.json
|
||||
Some(path) => path.join(".cache/spotify_player/credentials.json"),
|
||||
None => {
|
||||
warn!("Cannot determine home directory for credentials file.");
|
||||
// Parse the arguments
|
||||
let args = match parse_arguments(&env::args().collect()) {
|
||||
Ok(a) => a,
|
||||
Err(e) => {
|
||||
error!("Error parsing arguments: {}", e);
|
||||
exit(1);
|
||||
}
|
||||
};
|
||||
info!("Credentials file: {}", &credentials_file.display());
|
||||
|
||||
// TODO: If credentials file exists, confirm overwrite
|
||||
if credentials_file.exists() {
|
||||
warn!("Credentials file already exists: {}", &credentials_file.display());
|
||||
exit(1);
|
||||
}
|
||||
info!("Credentials file: {}", &args.path.display());
|
||||
|
||||
// TODO: If spotifyd is running, ask if shutdown is desired
|
||||
|
||||
let username = match env::consts::OS {
|
||||
|
||||
// Figure out the username
|
||||
let mut username = match env::consts::OS {
|
||||
"windows" => env::var("USERNAME"),
|
||||
_ => env::var("USER"),
|
||||
}.unwrap_or_else(|_| "unknown".to_string());
|
||||
}
|
||||
// Trim whitespace from the username
|
||||
.map(|u| u.trim().to_string())
|
||||
.unwrap_or("unknown".to_string());
|
||||
|
||||
// Default the username to 'unknown' if it doesn't fit the expected format
|
||||
if username != "unknown" {
|
||||
let valid_characters = r"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
|
||||
if match &username {
|
||||
u if u.is_empty() => {
|
||||
warn!("Cannot determine username, defaulting to 'unknown'");
|
||||
true
|
||||
}
|
||||
u if u.len() > 20 => {
|
||||
warn!("Username is too long, defaulting to 'unknown'");
|
||||
true
|
||||
}
|
||||
u if u.len() < 2 => {
|
||||
warn!("Username is too short, defaulting to 'unknown'");
|
||||
true
|
||||
}
|
||||
u if u.contains(|c| !valid_characters.contains(c)) => {
|
||||
warn!("Username contains invalid characters, defaulting to 'unknown'");
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
} {
|
||||
username = "unknown".to_string();
|
||||
}
|
||||
}
|
||||
|
||||
// Create the device metadata
|
||||
let device_name = format!("spotify-quickauth-{}", username);
|
||||
let device_id = hex::encode(Sha1::digest(device_name.as_bytes()));
|
||||
let device_type = DeviceType::Computer;
|
||||
@@ -47,35 +179,30 @@ async fn main() {
|
||||
.launch()
|
||||
.unwrap();
|
||||
|
||||
println!("Open Spotify and select output device: {}", device_name);
|
||||
info!("Open Spotify and select output device: {}", device_name);
|
||||
|
||||
let mut written = false;
|
||||
while let Some(credentials) = server.next().await {
|
||||
let result = File::create("./credentials.json").and_then(|mut file| {
|
||||
// Check if file exists
|
||||
if args.path.exists() && !args.force {
|
||||
warn!("Output file already exists (appeared after startup), use -f to overwrite");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Write the credentials to the file
|
||||
let result = File::create(&args.path).and_then(|mut file| {
|
||||
let data = serde_json::to_string(&credentials)?;
|
||||
write!(file, "{data}")
|
||||
});
|
||||
written = true;
|
||||
|
||||
// Check if the file was created successfully
|
||||
if let Err(e) = result {
|
||||
warn!("Cannot save credentials to cache: {}", e);
|
||||
exit(1);
|
||||
} else {
|
||||
println!("Credentials saved: {}", &credentials_file.display());
|
||||
info!("Credentials saved: {}", &args.path.display());
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
if !written {
|
||||
warn!("No credentials were written.");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mod tests {
|
||||
#[test]
|
||||
fn test_nothing() {
|
||||
assert_eq!(1, 1);
|
||||
}
|
||||
}
|
||||
mod tests {}
|
||||
|
||||
Reference in New Issue
Block a user