A decentralized music tracking and discovery platform built on AT Protocol 🎵 rocksky.app
spotify atproto lastfm musicbrainz scrobbling listenbrainz

[tracklist] implement tracklist.addTracks function

+52 -2
+1
apps/api/src/context.ts
··· 34 34 analytics: axios.create({ baseURL: env.ANALYTICS }), 35 35 dropbox: axios.create({ baseURL: env.DROPBOX }), 36 36 googledrive: axios.create({ baseURL: env.GOOGLE_DRIVE }), 37 + tracklist: axios.create({ baseURL: env.TRACKLIST }), 37 38 redis: await redis 38 39 .createClient({ url: env.REDIS_URL }) 39 40 .on("error", (err) => {
+1
apps/api/src/lib/env.ts
··· 33 33 GOOGLE_REDIRECT_URI: str({}), 34 34 GOOGLE_DRIVE: str({ default: "http://localhost:7880" }), 35 35 DROPBOX: str({ default: "http://localhost:7881" }), 36 + TRACKLIST: str({ default: "http://localhost:7884" }), 36 37 REDIS_URL: str({ default: "redis://localhost:6379" }), 37 38 PRIVATE_KEY_1: str({}), 38 39 PRIVATE_KEY_2: str({}),
+2 -2
apps/api/src/xrpc/app/rocksky/player/addItemsToQueue.ts
··· 3 3 import { Effect, pipe } from "effect"; 4 4 import { Server } from "lexicon"; 5 5 import { QueryParams } from "lexicon/types/app/rocksky/player/addItemsToQueue"; 6 - import tables from "schema"; 7 6 8 7 export default function (server: Server, ctx: Context) { 9 8 const addItemsToQueue = (params, auth: HandlerAuth) => ··· 42 41 Effect.tryPromise({ 43 42 try: async () => { 44 43 await ctx.db.transaction(async (tx) => { 45 - await tx.select().from(tables.queueTracks).execute(); 44 + // await tx.select().from(tables.queueTracks).execute(); 46 45 // Logic to add items to the queue would go here 46 + // await ctx.tracklist.post("/tracklist.addTrack"); 47 47 }); 48 48 }, 49 49 catch: (err) => {
+13
crates/tracklist/src/handlers/tracklist.rs
··· 20 20 Ok(HttpResponse::Ok().json(web::Json(json!(new_queue)))) 21 21 } 22 22 23 + pub async fn add_tracks( 24 + payload: &mut web::Payload, 25 + _req: &HttpRequest, 26 + client: Arc<redis::Client>, 27 + ) -> Result<HttpResponse, Error> { 28 + let body = read_payload!(payload); 29 + let params = serde_json::from_slice::<AddTracksParams>(&body)?; 30 + 31 + let new_queue = queue::add_tracks(&client, &params.did, params.track_ids).await?; 32 + 33 + Ok(HttpResponse::Ok().json(web::Json(json!(new_queue)))) 34 + } 35 + 23 36 pub async fn insert_track_at( 24 37 payload: &mut web::Payload, 25 38 _req: &HttpRequest,
+29
crates/tracklist/src/queue.rs
··· 17 17 Ok(queue) 18 18 } 19 19 20 + pub async fn add_tracks( 21 + client: &redis::Client, 22 + did: &str, 23 + track_ids: Vec<String>, 24 + ) -> Result<Vec<String>, Error> { 25 + let mut conn = client.get_multiplexed_async_connection().await?; 26 + 27 + conn.rpush::<_, _, i32>(format!("user:{}:queue", did), track_ids) 28 + .await?; 29 + 30 + let queue: Vec<String> = conn.lrange(format!("user:{}:queue", did), 0, -1).await?; 31 + 32 + Ok(queue) 33 + } 34 + 20 35 pub async fn insert_track_at( 21 36 client: &redis::Client, 22 37 did: &str, ··· 276 291 assert_eq!(queue, vec![track_id, track_id2]); 277 292 278 293 // Cleanup 294 + cleanup(&client, &did).await?; 295 + Ok(()) 296 + } 297 + 298 + #[tokio::test] 299 + async fn test_add_tracks() -> Result<(), Error> { 300 + let client = setup_redis().await; 301 + let did = Uuid::new_v4().to_string(); 302 + 303 + let track_ids = vec!["track:67890", "track:67891", "track:67892"]; 304 + add_tracks(&client, &did, track_ids.iter().map(|s| s.to_string()).collect()).await?; 305 + 306 + let queue = get_queue(&client, &did).await?; 307 + assert_eq!(queue, track_ids); 279 308 cleanup(&client, &did).await?; 280 309 Ok(()) 281 310 }
+6
crates/tracklist/src/types.rs
··· 7 7 } 8 8 9 9 #[derive(Debug, Serialize, Deserialize)] 10 + pub struct AddTracksParams { 11 + pub did: String, 12 + pub track_ids: Vec<String>, 13 + } 14 + 15 + #[derive(Debug, Serialize, Deserialize)] 10 16 pub struct InsertTrackAtParams { 11 17 pub did: String, 12 18 pub track_id: String,