diff --git a/Cargo.lock b/Cargo.lock index 6d04902..14646ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -48,6 +48,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "aligned" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "377e4c0ba83e4431b10df45c1d4666f178ea9c552cac93e60c3a88bf32785923" +dependencies = [ + "as-slice", +] + [[package]] name = "aligned-vec" version = "0.6.4" @@ -172,6 +181,15 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" +[[package]] +name = "as-slice" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516" +dependencies = [ + "stable_deref_trait", +] + [[package]] name = "ash" version = "0.38.0+1.3.281" @@ -503,6 +521,26 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "av-scenechange" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f321d77c20e19b92c39e7471cf986812cbb46659d2af674adc4331ef3f18394" +dependencies = [ + "aligned", + "anyhow", + "arg_enum_proc_macro", + "arrayvec", + "log", + "num-rational", + "num-traits", + "pastey", + "rayon", + "thiserror 2.0.17", + "v_frame", + "y4m", +] + [[package]] name = "av1-grain" version = "0.2.5" @@ -587,9 +625,12 @@ checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "bitstream-io" -version = "2.6.0" +version = "4.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" +checksum = "60d4bd9d1db2c6bdf285e223a7fa369d5ce98ec767dec949c6ca62863ce61757" +dependencies = [ + "core2", +] [[package]] name = "blade-graphics" @@ -695,6 +736,12 @@ dependencies = [ "piper", ] +[[package]] +name = "blurhash" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79769241dcd44edf79a732545e8b5cec84c247ac060f5252cd51885d093a8fc" + [[package]] name = "bstr" version = "1.12.1" @@ -731,9 +778,9 @@ dependencies = [ [[package]] name = "built" -version = "0.7.7" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" +checksum = "f4ad8f11f288f48ca24471bbd51ac257aaeaaa07adae295591266b792902ae64" [[package]] name = "bumpalo" @@ -862,16 +909,6 @@ dependencies = [ "nom 7.1.3", ] -[[package]] -name = "cfg-expr" -version = "0.15.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" -dependencies = [ - "smallvec", - "target-lexicon", -] - [[package]] name = "cfg-if" version = "1.0.4" @@ -1230,6 +1267,15 @@ dependencies = [ "metal", ] +[[package]] +name = "core2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" +dependencies = [ + "memchr", +] + [[package]] name = "core_maths" version = "0.1.1" @@ -2078,9 +2124,9 @@ dependencies = [ [[package]] name = "gif" -version = "0.13.3" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b" +checksum = "f954a9e9159ec994f73a30a12b96a702dde78f5547bcb561174597924f7d4162" dependencies = [ "color_quant", "weezl", @@ -2764,9 +2810,9 @@ dependencies = [ [[package]] name = "image" -version = "0.25.8" +version = "0.25.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "529feb3e6769d234375c4cf1ee2ce713682b8e76538cb13f9fc23e1400a591e7" +checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a" dependencies = [ "bytemuck", "byteorder-lite", @@ -2782,8 +2828,8 @@ dependencies = [ "rayon", "rgb", "tiff", - "zune-core", - "zune-jpeg", + "zune-core 0.5.0", + "zune-jpeg 0.5.5", ] [[package]] @@ -2943,15 +2989,6 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.13.0" @@ -2981,11 +3018,14 @@ name = "jello" version = "0.1.0" dependencies = [ "api", + "blurhash", "clap", "clap_complete", "dotenvy", "error-stack", "gpui", + "image", + "tap", "thiserror 2.0.17", "tokio", "tracing", @@ -3234,6 +3274,15 @@ dependencies = [ "libc", ] +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + [[package]] name = "maybe-rayon" version = "0.1.1" @@ -3839,6 +3888,12 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pastey" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" + [[package]] name = "pathdiff" version = "0.2.3" @@ -4305,19 +4360,21 @@ checksum = "f93e7e49bb0bf967717f7bd674458b3d6b0c5f48ec7e3038166026a69fc22223" [[package]] name = "rav1e" -version = "0.7.1" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" +checksum = "43b6dd56e85d9483277cde964fd1bdb0428de4fec5ebba7540995639a21cb32b" dependencies = [ + "aligned-vec", "arbitrary", "arg_enum_proc_macro", "arrayvec", + "av-scenechange", "av1-grain", "bitstream-io", "built", "cfg-if", "interpolate_name", - "itertools 0.12.1", + "itertools 0.14.0", "libc", "libfuzzer-sys", "log", @@ -4326,23 +4383,21 @@ dependencies = [ "noop_proc_macro", "num-derive", "num-traits", - "once_cell", "paste", "profiling", - "rand 0.8.5", - "rand_chacha 0.3.1", + "rand 0.9.2", + "rand_chacha 0.9.0", "simd_helpers", - "system-deps", - "thiserror 1.0.69", + "thiserror 2.0.17", "v_frame", "wasm-bindgen", ] [[package]] name = "ravif" -version = "0.11.20" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5825c26fddd16ab9f515930d49028a630efec172e903483c94796cfe31893e6b" +checksum = "ef69c1990ceef18a116855938e74793a5f7496ee907562bd0857b6ac734ab285" dependencies = [ "avif-serialize", "imgref", @@ -5435,19 +5490,6 @@ dependencies = [ "libc", ] -[[package]] -name = "system-deps" -version = "6.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" -dependencies = [ - "cfg-expr", - "heck 0.5.0", - "pkg-config", - "toml 0.8.23", - "version-compare", -] - [[package]] name = "taffy" version = "0.9.0" @@ -5472,12 +5514,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" -[[package]] -name = "target-lexicon" -version = "0.12.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" - [[package]] name = "tempfile" version = "3.23.0" @@ -5571,7 +5607,7 @@ dependencies = [ "half", "quick-error", "weezl", - "zune-jpeg", + "zune-jpeg 0.4.21", ] [[package]] @@ -5906,10 +5942,14 @@ version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" dependencies = [ + "matchers", "nu-ansi-term", + "once_cell", + "regex-automata", "sharded-slab", "smallvec", "thread_local", + "tracing", "tracing-core", "tracing-log", ] @@ -6197,12 +6237,6 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" -[[package]] -name = "version-compare" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" - [[package]] name = "version_check" version = "0.9.5" @@ -6970,6 +7004,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" +[[package]] +name = "y4m" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448" + [[package]] name = "yazi" version = "0.2.1" @@ -7266,6 +7306,12 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" +[[package]] +name = "zune-core" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "111f7d9820f05fd715df3144e254d6fc02ee4088b0644c0ffd0efc9e6d9d2773" + [[package]] name = "zune-inflate" version = "0.2.54" @@ -7281,7 +7327,16 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" dependencies = [ - "zune-core", + "zune-core 0.4.12", +] + +[[package]] +name = "zune-jpeg" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6fb7703e32e9a07fb3f757360338b3a567a5054f21b5f52a666752e333d58e" +dependencies = [ + "zune-core 0.5.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index ddb5d38..5371af1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,12 +9,15 @@ license = "MIT" [dependencies] api = { version = "0.1.0", path = "api" } +blurhash = "0.2.3" clap = { version = "4.5", features = ["derive"] } clap_complete = "4.5" dotenvy = "0.15.7" error-stack = "0.6" gpui = { version = "0.2.2", default-features = false, features = ["wayland"] } +image = "0.25.9" +tap = "1.0.1" thiserror = "2.0" tokio = { version = "1.43.1", features = ["macros", "rt-multi-thread"] } tracing = "0.1" -tracing-subscriber = "0.3" +tracing-subscriber = { version = "0.3", features = ["env-filter"] } diff --git a/src/ui.rs b/src/ui.rs index ed6321f..ed8a323 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,18 +1,20 @@ -mod movies; -mod player; -mod series; +// mod movies; +// mod player; +// mod series; +use ::tap::*; -use std::collections::BTreeMap; +use std::{collections::BTreeMap, sync::Arc}; use gpui::{ - App, Application, Bounds, ClickEvent, Context, SharedString, Window, WindowBounds, - WindowOptions, actions, div, prelude::*, px, rgb, size, + App, Application, Bounds, ClickEvent, Context, ImageId, ImageSource, RenderImage, Resource, + SharedString, Window, WindowBounds, WindowOptions, actions, div, prelude::*, px, rgb, size, }; #[derive(Clone, Debug)] pub struct AppState { pub title: SharedString, pub items: BTreeMap, + pub item_ids: BTreeMap, pub current_item: Option, pub errors: Vec, pub jellyfin_client: api::JellyfinClient, @@ -47,6 +49,7 @@ impl AppState { AppState { title: SharedString::new(title.as_ref()), items: BTreeMap::new(), + item_ids: BTreeMap::new(), current_item: None, errors: Vec::new(), jellyfin_client, @@ -64,7 +67,10 @@ impl AppState { fn load_item(id: usize) -> impl Fn(&mut Self, &ClickEvent, &mut Window, &mut Context) { move |state: &mut Self, event: &ClickEvent, window: &mut Window, cx: &mut Context| { - dbg!("Loading item with ID: {}", id); + let item_id = id; + cx.spawn(async move |entity, app| { + tracing::info!("Loading item with id: {}", item_id); + }); } } @@ -183,3 +189,77 @@ pub fn ui(jellyfin_client: api::JellyfinClient) { .expect("Failed to open window"); }) } + +#[derive(Clone, Debug)] +pub struct Card { + pub id: usize, + pub title: SharedString, + pub description: SharedString, + pub image: SharedString, + pub image_blurhash: BlurHash, + pub media_type: SharedString, + pub loading: bool, +} + +impl Render for Card { + fn render(&mut self, _window: &mut Window, _cx: &mut Context) -> impl IntoElement { + div() + .id(self.id) + .flex() + .flex_col() + .w_48() + .h_64() + .p_10() + .bg(rgb(0xff00ff)) + .rounded_lg() + .pipe(|card| { + if self.loading { + card.child(self.image_blurhash.clone()) + } else { + card.child(gpui::img(self.image.clone())) + } + }) + } +} + +#[derive(Clone, Debug)] +pub struct BlurHash { + pub id: ImageId, + pub data: Arc, +} + +impl BlurHash { + pub fn new( + data: impl AsRef, + width: u32, + height: u32, + punch: f32, + ) -> Result> { + use error_stack::ResultExt; + let decoded = + blurhash::decode(data.as_ref(), width, height, punch).change_context(crate::Error)?; + let buffer = image::RgbaImage::from_raw(width, height, decoded) + .ok_or(crate::Error) + .attach("Failed to convert")?; + let frame = image::Frame::new(buffer); + let render_image = RenderImage::new([frame]); + Ok(Self { + id: render_image.id, + data: Arc::from(render_image), + }) + } +} + +impl Render for BlurHash { + fn render(&mut self, _window: &mut Window, _cx: &mut Context) -> impl IntoElement { + gpui::img(ImageSource::Render(self.data.clone())) + } +} + +impl IntoElement for BlurHash { + type Element = gpui::Img; + + fn into_element(self) -> Self::Element { + gpui::img(ImageSource::Render(self.data.clone())) + } +}