Access The Spotify API From A Tauri App
Notes
This is how I'm connecting to the
It's bare bones prototype code
The code produces an app with a working login/logout button that also shows the user id when logged in
The files are based of a standard `cargo create-tauri-app` run with JavaScript for the front end language
More error handling is a good idea
The
The only thing I did outside this code was create an app in the
The code uses the
FILE: src/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script type="module">
import {SpotifyControl} from "./main.js"
document.addEventListener('DOMContentLoaded', async () => {
const sc = new SpotifyControl()
sc.init()
})
</script>
</head>
<body>
<div id="auth_button_holder"></div>
</body>
</html>
FILE: src/main.js
const { invoke } = window.__TAURI__.tauri;
class SpotifyControl {
constructor() { }
async init() {
let user_id = await invoke('user_id')
if (user_id) {
this.make_logout_button(user_id)
}
else {
const urlParams = new URLSearchParams(window.location.search)
let code = urlParams.get('code')
if (code) {
await invoke("process_auth_code", { url: window.location.href })
window.location.href = '/'
}
this.make_login_button()
}
}
make_login_button() {
while (auth_button_holder.children.length > 0) {
auth_button_holder.children[0].remove()
}
const login_button = document.createElement('button')
login_button.innerText = 'login'
login_button.addEventListener('click', async () => {
window.location.href = await invoke('start_login')
})
auth_button_holder.appendChild(login_button)
}
make_logout_button(user_id) {
while (auth_button_holder.children.length > 0) {
auth_button_holder.children[0].remove()
}
const name_badge = document.createElement('div')
name_badge.innerHTML = user_id
auth_button_holder.appendChild(name_badge)
const logout_button = document.createElement('button')
logout_button.innerText = 'logout'
logout_button.addEventListener('click', async () => {
await invoke("logout")
window.location.href = '/'
})
auth_button_holder.appendChild(logout_button)
}
}
export { SpotifyControl }
FILE: src-tuari/Cargo.toml
[package]
name = "spotify_test"
version = "0.0.1"
description = "Spotify API Test App"
authors = ["Alan W. Smith"]
license = "MIT"
edition = "2021"
[build-dependencies]
tauri-build = { version = "1.5", features = [] }
[dependencies]
tauri = { version = "1.5", features = ["shell-open"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
rspotify = { version = "0.12.0", default-features = false, features = ["client-ureq", "ureq-rustls-tls"] }
[features]
custom-protocol = ["tauri/custom-protocol"]
FILE: src-tauri/src/main.rs
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use rspotify::{prelude::*, scopes, AuthCodePkceSpotify, Credentials, OAuth};
use std::sync::Mutex;
use tauri::Manager;
use tauri::State;
struct Storage {
spotify: Mutex<AuthCodePkceSpotify>,
user_id: Mutex<Option<String>>,
}
#[tauri::command]
fn logout(store: State<'_, Storage>) {
let mut uid = store.user_id.lock().unwrap();
*uid = None
}
#[tauri::command]
fn process_auth_code(url: String, store: State<'_, Storage>) -> Result<String, ()> {
let s = store.spotify.lock().unwrap();
let _ = s.request_token(s.parse_response_code(&url).unwrap().as_ref());
let user = s.me();
match user {
Ok(data) => {
let mut uid = store.user_id.lock().unwrap();
*uid = Some(data.id.id().to_string());
}
Err(_) => {}
}
Ok(format!("{}", &url))
}
#[tauri::command]
fn start_login(store: State<Storage>) -> String {
let mut s = store.spotify.lock().unwrap();
let url = s.get_authorize_url(None).unwrap();
format!("{}", &url)
}
#[tauri::command]
fn user_id(store: State<'_, Storage>) -> Option<String> {
let uid = store.user_id.lock().unwrap();
uid.as_ref().cloned()
}
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![
logout,
process_auth_code,
start_login,
user_id,
])
.setup(|app| {
{
let window = app.get_window("main").unwrap();
window.open_devtools();
}
Ok(())
})
.manage(Storage {
spotify: Mutex::new(AuthCodePkceSpotify::new(
Credentials::new_pkce("YOUR_CLIENT_ID"),
OAuth {
redirect_uri: "http://127.0.0.1:1430/".to_string(),
scopes: scopes!("user-read-private user-read-email"),
..Default::default()
},
)),
user_id: Mutex::new(None),
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}