mirror of
https://github.com/Xevion/spotify-quickauth.git
synced 2025-12-14 02:13:12 -06:00
initial discovery implementation
This commit is contained in:
3099
Cargo.lock
generated
3099
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
12
Cargo.toml
12
Cargo.toml
@@ -4,3 +4,15 @@ version = "0.0.5"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
librespot-discovery = { git = "https://github.com/librespot-org/librespot", branch = "dev" }
|
||||||
|
librespot-core = { git = "https://github.com/librespot-org/librespot", branch = "dev" }
|
||||||
|
serde = { version = "1.0.210", features = ["derive"] }
|
||||||
|
tokio = { version = "1.40.0", features = ["full"] }
|
||||||
|
futures = "0.3.30"
|
||||||
|
serde_json = "1.0.128"
|
||||||
|
sha1 = "0.10.6"
|
||||||
|
hex = "0.4.3"
|
||||||
|
log = "0.4.22"
|
||||||
|
hex-literal = "0.4.1"
|
||||||
|
home = "0.5.9"
|
||||||
|
env_logger = "0.11.5"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ A simple CLI-based application for creating a `credentials.json` file, used by t
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
You can install this applicaiton, but most people will just need it once.
|
You can install this application, but most people will just need it once. The following commands will run the application without installing it.
|
||||||
|
|
||||||
For Linux and macOS, you can paste this command into your terminal:
|
For Linux and macOS, you can paste this command into your terminal:
|
||||||
|
|
||||||
|
|||||||
130
src/main.rs
130
src/main.rs
@@ -1,82 +1,74 @@
|
|||||||
use std::env;
|
use std::{env, fs::File, process::exit};
|
||||||
use std::process::Command;
|
|
||||||
|
|
||||||
fn main() {
|
use futures::StreamExt;
|
||||||
let os = env::consts::OS;
|
use librespot_core::config::DeviceType;
|
||||||
let arch = env::consts::ARCH;
|
use librespot_discovery::Discovery;
|
||||||
let username = if os == "windows" {
|
use log::{info, warn};
|
||||||
env::var("USERNAME").unwrap_or_else(|_| "unknown".to_string())
|
use sha1::{Digest, Sha1};
|
||||||
} else {
|
use librespot_core::SessionConfig;
|
||||||
env::var("USER").unwrap_or_else(|_| "unknown".to_string())
|
use std::io::Write;
|
||||||
|
|
||||||
|
#[tokio::main(flavor = "current_thread")]
|
||||||
|
async fn main() {
|
||||||
|
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.");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let hostname = Command::new("hostname")
|
info!("Credentials file: {}", &credentials_file.display());
|
||||||
.output()
|
|
||||||
.map(|output| String::from_utf8_lossy(&output.stdout).trim().to_string())
|
|
||||||
.unwrap_or_else(|_| "unknown".to_string());
|
|
||||||
let execution_path = env::current_exe()
|
|
||||||
.map(|path| path.display().to_string())
|
|
||||||
.unwrap_or_else(|_| "unknown".to_string());
|
|
||||||
let working_directory = env::current_dir()
|
|
||||||
.map(|path| path.display().to_string())
|
|
||||||
.unwrap_or_else(|_| "unknown".to_string());
|
|
||||||
|
|
||||||
println!(
|
// TODO: If credentials file exists, confirm overwrite
|
||||||
"{}@{} ({}/{}) [{}] [{}]",
|
if credentials_file.exists() {
|
||||||
username, hostname, os, arch, working_directory, execution_path
|
warn!("Credentials file already exists: {}", &credentials_file.display());
|
||||||
);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: If spotifyd is running, ask if shutdown is desired
|
||||||
|
|
||||||
#[cfg(test)]
|
let username = match env::consts::OS {
|
||||||
mod tests {
|
"windows" => env::var("USERNAME"),
|
||||||
use super::*;
|
_ => env::var("USER"),
|
||||||
|
}.unwrap_or_else(|_| "unknown".to_string());
|
||||||
|
|
||||||
#[test]
|
let device_name = format!("spotify-quickauth-{}", username);
|
||||||
fn test_os_arch() {
|
let device_id = hex::encode(Sha1::digest(device_name.as_bytes()));
|
||||||
let os = env::consts::OS;
|
let device_type = DeviceType::Computer;
|
||||||
let arch = env::consts::ARCH;
|
|
||||||
|
|
||||||
// Make sure that OS and ARCH are not empty
|
let mut server = Discovery::builder(device_id, SessionConfig::default().client_id)
|
||||||
assert!(!os.is_empty());
|
.name(device_name.clone())
|
||||||
assert!(!arch.is_empty());
|
.device_type(device_type)
|
||||||
}
|
.launch()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
#[test]
|
println!("Open Spotify and select output device: {}", device_name);
|
||||||
fn test_username() {
|
|
||||||
let username = env::var("USER").unwrap_or_else(|_| "unknown".to_string());
|
|
||||||
|
|
||||||
// In CI environments, USER might not be set, so allow "unknown"
|
let mut written = false;
|
||||||
assert!(!username.is_empty());
|
while let Some(credentials) = server.next().await {
|
||||||
}
|
let result = File::create(&credentials_file).and_then(|mut file| {
|
||||||
|
let data = serde_json::to_string(&credentials)?;
|
||||||
|
write!(file, "{data}")
|
||||||
|
});
|
||||||
|
written = true;
|
||||||
|
|
||||||
#[test]
|
if let Err(e) = result {
|
||||||
fn test_hostname() {
|
warn!("Cannot save credentials to cache: {}", e);
|
||||||
let hostname = Command::new("hostname")
|
exit(1);
|
||||||
.output()
|
} else {
|
||||||
.map(|output| String::from_utf8_lossy(&output.stdout).trim().to_string())
|
println!("Credentials saved: {}", &credentials_file.display());
|
||||||
.unwrap_or_else(|_| "unknown".to_string());
|
exit(0);
|
||||||
|
}
|
||||||
// Since hostname might vary, just ensure it's not empty
|
}
|
||||||
assert!(!hostname.is_empty());
|
|
||||||
}
|
if !written {
|
||||||
|
warn!("No credentials were written.");
|
||||||
#[test]
|
exit(1);
|
||||||
fn test_execution_path() {
|
|
||||||
let execution_path = env::current_exe()
|
|
||||||
.map(|path| path.display().to_string())
|
|
||||||
.unwrap_or_else(|_| "unknown".to_string());
|
|
||||||
|
|
||||||
// Ensure execution path is not "unknown" when it's expected to resolve
|
|
||||||
assert!(execution_path != "unknown");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_working_directory() {
|
|
||||||
let working_directory = env::current_dir()
|
|
||||||
.map(|path| path.display().to_string())
|
|
||||||
.unwrap_or_else(|_| "unknown".to_string());
|
|
||||||
|
|
||||||
// Ensure the working directory is a valid path
|
|
||||||
assert!(working_directory != "unknown");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user