forked from
rocksky.app/rocksky
A decentralized music tracking and discovery platform built on AT Protocol 馃幍
1use anyhow::Error;
2use reqwest::Client;
3
4use crate::{auth::generate_token, cache::Cache, types::Track};
5
6const ROCKSKY_API: &str = "https://api.rocksky.app";
7
8pub async fn scrobble(cache: &Cache, did: &str, track: Track, timestamp: u64) -> Result<(), Error> {
9 let key = format!(
10 "{} - {}",
11 track.artist.to_lowercase(),
12 track.title.to_lowercase()
13 );
14
15 // Check if the track is already in the cache, if not add it
16 if !cache.exists(&key)? {
17 let value = serde_json::to_string(&track)?;
18 let ttl = 15 * 60; // 15 minutes
19 cache.setex(&key, &value, ttl)?;
20 }
21
22 let mut track = track;
23 track.timestamp = Some(timestamp);
24
25 let token = generate_token(did)?;
26 let client = Client::new();
27
28 tracing::info!(did = %did, track = ?track, "Scrobbling track");
29
30 let response = client
31 .post(&format!("{}/now-playing", ROCKSKY_API))
32 .bearer_auth(token)
33 .json(&track)
34 .send()
35 .await?;
36
37 let status = response.status();
38 tracing::info!(did = %did, artist = %track.artist, track = %track.title, status = %status, "Scrobble response");
39 if !status.is_success() {
40 let response_text = response.text().await?;
41 tracing::error!(did = %did, response = %response_text, "Failed to scrobble track");
42 return Err(Error::msg(format!(
43 "Failed to scrobble track: {}",
44 response_text
45 )));
46 }
47
48 Ok(())
49}