From abb87ec67c997fd385f410444bef2df19a83f576 Mon Sep 17 00:00:00 2001 From: Neshura Date: Sat, 17 Feb 2024 02:13:48 +0100 Subject: [PATCH] Basic Sycamore Setup (Credentials Removed) --- index.html | 11 ++ src/components/mod.rs | 3 + src/components/separator/mod.rs | 26 +++++ src/main.rs | 201 ++++++++++++++++++++++++++++++++ styles.css | 24 ++++ 5 files changed, 265 insertions(+) create mode 100644 index.html create mode 100644 src/components/mod.rs create mode 100644 src/components/separator/mod.rs create mode 100644 src/main.rs create mode 100644 styles.css diff --git a/index.html b/index.html new file mode 100644 index 0000000..1276eb1 --- /dev/null +++ b/index.html @@ -0,0 +1,11 @@ + + + + + + Music App + + + + + \ No newline at end of file diff --git a/src/components/mod.rs b/src/components/mod.rs new file mode 100644 index 0000000..d365263 --- /dev/null +++ b/src/components/mod.rs @@ -0,0 +1,3 @@ +pub use separator::separator; + +mod separator; \ No newline at end of file diff --git a/src/components/separator/mod.rs b/src/components/separator/mod.rs new file mode 100644 index 0000000..d7ea1fd --- /dev/null +++ b/src/components/separator/mod.rs @@ -0,0 +1,26 @@ +use sycamore::prelude::*; + +#[derive(Props)] +pub struct SeparatorProps { + width: u8 +} + +/* + w-[1%] w-[2%] w-[3%] w-[4%] w-[5%] w-[6%] w-[7%] w-[8%] w-[9%] w-[10%] + w-[11%] w-[12%] w-[13%] w-[14%] w-[15%] w-[16%] w-[17%] w-[18%] w-[19%] w-[20%] + w-[21%] w-[22%] w-[23%] w-[24%] w-[25%] w-[26%] w-[27%] w-[28%] w-[29%] w-[30%] + w-[31%] w-[32%] w-[33%] w-[34%] w-[35%] w-[36%] w-[37%] w-[38%] w-[39%] w-[40%] + w-[41%] w-[42%] w-[43%] w-[44%] w-[45%] w-[46%] w-[47%] w-[48%] w-[49%] w-[50%] + w-[51%] w-[52%] w-[53%] w-[54%] w-[55%] w-[56%] w-[57%] w-[58%] w-[59%] w-[60%] + w-[61%] w-[62%] w-[63%] w-[64%] w-[65%] w-[66%] w-[67%] w-[68%] w-[69%] w-[70%] + w-[71%] w-[72%] w-[73%] w-[74%] w-[75%] w-[76%] w-[77%] w-[78%] w-[79%] w-[80%] + w-[81%] w-[82%] w-[83%] w-[84%] w-[85%] w-[86%] w-[87%] w-[88%] w-[89%] w-[90%] + w-[91%] w-[92%] w-[93%] w-[94%] w-[95%] w-[96%] w-[97%] w-[98%] w-[99%] w-[100%] +*/ + +pub fn separator(props: SeparatorProps) -> View { + let class_string = format!("place-self-center w-[{}%] border border-1 border-black", props.width); + view! { + p(class=class_string) {} + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..b2252be --- /dev/null +++ b/src/main.rs @@ -0,0 +1,201 @@ +mod components; + +use std::env; +use sycamore::prelude::*; +use sycamore::futures::spawn_local_scoped; +use serde::Deserialize; +use log::{info, warn, error, Level, debug}; + +fn main() { + console_log::init_with_level(Level::Debug).expect("Something went horribly wrong while setting the Logging Level"); + + sycamore::render(|| view! { + div(class="flex flex-col h-full") { + div(class="min-w-full p-1 debug") { + h1 { "Navbar" } + } + div(class="flex-1 grid grid-cols-5 debug") { + div(class="col-span-1 debug") { + h1 { "Left Sidebar" } + } + div(class="col-span-3 debug") { + h1 { "Center Module" } + } + div(class="col-span-1 flex flex-col gap-1 p-2 debug") { + div(class="flex flex-row w-full gap-2 items-center") { + h1(class="flex flex-1") { "Current Queue" } + p { "Fetch" } + p { "Upload" } + } + components::separator(width = 100) + crate::render_playlist {} + } + } + div(class="min-h-24 h-24 debug") { + h3 { "Player Module" } + } + } + }); +} + +#[derive(Deserialize)] +struct PlayQueueApi { + #[serde(alias="subsonic-response")] + subsonic_response: SubsonicResponse +} + +#[derive(Deserialize)] +struct SubsonicResponse { + status: String, + version: String, + r#type: String, + #[serde(alias="serverVersion")] + server_version: String, + #[serde(alias="openSubsonic")] + open_subsonic: bool, + #[serde(alias="playQueue")] + play_queue: PlayQueue, +} + +#[derive(Debug, Deserialize)] +struct PlayQueue { + entry: Vec, + current: Option, + position: Option, + username: String, + changed: String, + #[serde(alias="changedBy")] + changed_by: String +} + +#[derive(Clone, Debug, Deserialize)] +struct Song { + id: String, + parent: String, + #[serde(alias="isDir")] + is_dir: bool, + title: String, + album: String, + artist: String, + track: usize, + year: usize, + genre: String, + genres: Vec, + #[serde(alias="coverArt")] + cover_art: String, + size: usize, + #[serde(alias="contentType")] + content_type: String, + suffix: String, + duration: usize, + #[serde(alias="bitRate")] + bit_rate: usize, + path: String, + #[serde(alias="playCount")] + play_count: usize, + played: String, + #[serde(alias="discNumber")] + disc_number: usize, + created: String, + #[serde(alias="albumId")] + album_id: String, + #[serde(alias="artistId")] + artist_id: String, + r#type: String, + #[serde(alias="userRating")] + user_rating: Option, + #[serde(alias="isVideo")] + is_video: bool, + bpm: usize, + comment: String +} + +#[derive(Debug, Clone, Deserialize)] +struct Genre { + name: String +} + +async fn test_api() -> Vec { + const API_BASE: &str = "https://music.neshweb.net/rest"; + + + let salt = "testsalt1234"; // TODO: random salt please + + let salted_password = format!("{password}{salt}"); + + let hash = md5::compute(salted_password.as_bytes()); + + let res = match reqwest::get(format!("{API_BASE}/getPlayQueue.view?u={user}&t={:x}&s={salt}&v=1.16.1&c={}&f=json", hash, env!("CARGO_PKG_NAME"))).await { + Ok(data) => data, + Err(e) => { + error!("Error: {e}"); + return vec![] + }, + }; + + debug!("Still alive!"); + + let data = match res.json::().await { + Ok(data) => data, + Err(e) => { + error!("Error: {e}"); + return vec![] + }, + }; + + + + data.subsonic_response.play_queue.entry.iter().map(|elem| { + elem.clone() + }).collect() + + /* + let res = reqwest::blocking::get(format!("{api_base}/getPlayQueue.view?u={user}&t={:x}&s={salt}&v=1.16.1&c=myapp&f=json", hash)).unwrap(); + + let text = res.text().unwrap(); + + println!("{text}"); + + let song_id = "81983bfae2fdddfa5d3dc181d61d987c"; + let song_pos = 1; + + let res_save = reqwest::blocking::get(format!("{api_base}/savePlayQueue.view?u={user}&t={:x}&s={salt}&v=1.16.1&c={}&f=json&id={song_id}&pos={song_pos}", hash, env!("CARGO_PKG_NAME"))).unwrap(); + + let text_save = res_save.text().unwrap(); + + println!("{text_save}");*/ +} + +#[component] +fn render_playlist() -> View { + let list: Signal> = create_signal(vec![]); + + info!("Info Test"); + debug!("Debug Test"); + + spawn_local_scoped(async move { + debug!("Moving into spawned task"); + let res = test_api().await; + debug!("Data from spawned task returned"); + list.set(res); + }); + + create_effect(move || { + debug!("List is: {:#?}", list.get_clone()); + }); + + view! { + (View::new_fragment(list.get_clone().iter().map(|elem: &Song| { + let song = elem.clone(); + view! { + p { (song.artist) " - " (song.title) " (" (seconds_to_duration(song.duration)) ")" } + } + }).collect())) + } +} + +fn seconds_to_duration(raw_seconds: usize) -> String { + let minutes = raw_seconds / 60; + let seconds = raw_seconds % 60; + format!("{minutes}:{seconds}") +} diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..2426beb --- /dev/null +++ b/styles.css @@ -0,0 +1,24 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + h1 { + @apply text-2xl; + @apply font-bold; + } + h2 { + @apply text-xl; + @apply font-bold; + } + h3 { + @apply text-lg; + @apply font-bold; + } +} + +.debug { + @apply border; + @apply border-2; + @apply border-black; +}