···24 "position": {
25 "type": "integer",
26 "description": "Position in the queue to insert the items at, defaults to the end if not specified"
000027 }
28 }
29 }
···24 "position": {
25 "type": "integer",
26 "description": "Position in the queue to insert the items at, defaults to the end if not specified"
27+ },
28+ "shuffle": {
29+ "type": "boolean",
30+ "description": "Whether to shuffle the added items in the queue"
31 }
32 }
33 }
···24 type = "integer"
25 description = "Position in the queue to insert the items at, defaults to the end if not specified"
26 }
000027 }
28 }
29 }
···24 type = "integer"
25 description = "Position in the queue to insert the items at, defaults to the end if not specified"
26 }
27+ ["shuffle"] = new BooleanType {
28+ type = "boolean"
29+ description = "Whether to shuffle the added items in the queue"
30+ }
31 }
32 }
33 }
+9
apps/api/pkl/defs/player/playDirectory.pkl
···16 ["directoryId"] = new StringType {
17 type = "string"
18 }
00000000019 }
20 }
21 }
···16 ["directoryId"] = new StringType {
17 type = "string"
18 }
19+ ["shuffle"] = new BooleanType {
20+ type = "boolean"
21+ }
22+ ["recurse"] = new BooleanType {
23+ type = "boolean"
24+ }
25+ ["position"] = new IntegerType {
26+ type = "integer"
27+ }
28 }
29 }
30 }
+13
apps/api/src/lexicon/lexicons.ts
···1892 description:
1893 'Position in the queue to insert the items at, defaults to the end if not specified',
1894 },
00001895 },
1896 },
1897 },
···2032 },
2033 directoryId: {
2034 type: 'string',
0000000002035 },
2036 },
2037 },
···1892 description:
1893 'Position in the queue to insert the items at, defaults to the end if not specified',
1894 },
1895+ shuffle: {
1896+ type: 'boolean',
1897+ description: 'Whether to shuffle the added items in the queue',
1898+ },
1899 },
1900 },
1901 },
···2036 },
2037 directoryId: {
2038 type: 'string',
2039+ },
2040+ shuffle: {
2041+ type: 'boolean',
2042+ },
2043+ recurse: {
2044+ type: 'boolean',
2045+ },
2046+ position: {
2047+ type: 'integer',
2048 },
2049 },
2050 },
···13 items: string[]
14 /** Position in the queue to insert the items at, defaults to the end if not specified */
15 position?: number
0016}
1718export type InputSchema = undefined
···13 items: string[]
14 /** Position in the queue to insert the items at, defaults to the end if not specified */
15 position?: number
16+ /** Whether to shuffle the added items in the queue */
17+ shuffle?: boolean
18}
1920export type InputSchema = undefined
···1+pub mod client;
2+pub mod cmd;
3+pub mod consts;
4+pub mod crypto;
5+pub mod handlers;
6+pub mod repo;
7+pub mod scan;
8+pub mod token;
9+pub mod types;
10+pub mod xata;
···1+pub mod client;
2+pub mod cmd;
3+pub mod consts;
4+pub mod crypto;
5+pub mod handlers;
6+pub mod repo;
7+pub mod scan;
8+pub mod token;
9+pub mod types;
10+pub mod xata;
···000000000000000001pub mod core;
2pub mod crypto;
3pub mod spotify;
4pub mod subscriber;
5pub mod types;
6pub mod xata;
000000000000000000000000000000000000000000
···1+use std::{
2+ env,
3+ sync::{Arc, Mutex},
4+};
5+6+use anyhow::Error;
7+use async_nats::connect;
8+use duckdb::Connection;
9+use owo_colors::OwoColorize;
10+use sqlx::postgres::PgPoolOptions;
11+12+use crate::{
13+ core::{create_tables, find_spotify_users, load_users, save_playlists},
14+ spotify::get_user_playlists,
15+ subscriber::subscribe,
16+};
17+18pub mod core;
19pub mod crypto;
20pub mod spotify;
21pub mod subscriber;
22pub mod types;
23pub mod xata;
24+25+pub async fn start() -> Result<(), Error> {
26+ let conn = Connection::open("./rocksky-playlists.ddb")?;
27+ let conn = Arc::new(Mutex::new(conn));
28+ create_tables(conn.clone())?;
29+30+ subscribe(conn.clone()).await?;
31+32+ let pool = PgPoolOptions::new()
33+ .max_connections(5)
34+ .connect(&env::var("XATA_POSTGRES_URL")?)
35+ .await?;
36+ let users = find_spotify_users(&pool, 0, 100).await?;
37+38+ load_users(conn.clone(), &pool).await?;
39+40+ sqlx::query(r#"
41+ CREATE UNIQUE INDEX IF NOT EXISTS user_playlists_unique_index ON user_playlists (user_id, playlist_id)
42+ "#)
43+ .execute(&pool)
44+ .await?;
45+ let conn = conn.clone();
46+47+ let addr = env::var("NATS_URL").unwrap_or_else(|_| "nats://localhost:4222".to_string());
48+ let nc = connect(&addr).await?;
49+ let nc = Arc::new(Mutex::new(nc));
50+ println!("Connected to NATS server at {}", addr.bright_green());
51+52+ for user in users {
53+ let token = user.1.clone();
54+ let did = user.2.clone();
55+ let user_id = user.3.clone();
56+ let playlists = get_user_playlists(token).await?;
57+ save_playlists(&pool, conn.clone(), nc.clone(), playlists, &user_id, &did).await?;
58+ }
59+60+ println!("Done!");
61+62+ loop {
63+ tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
64+ }
65+}
···1+pub mod analytics;
2+pub mod dropbox;
3+pub mod googledrive;
4+pub mod jetstream;
5+pub mod playlist;
6+pub mod scrobbler;
7+pub mod spotify;
8+pub mod tracklist;
9+pub mod webscrobbler;