diff options
-rw-r--r-- | Cargo.lock | 75 | ||||
-rw-r--r-- | Cargo.toml | 10 | ||||
-rw-r--r-- | client/Cargo.toml | 11 | ||||
-rw-r--r-- | client/src/lib.rs | 70 | ||||
-rw-r--r-- | server/Cargo.toml | 2 | ||||
-rw-r--r-- | server/src/routes/api/mod.rs | 24 | ||||
-rw-r--r-- | server/src/routes/stream.rs | 54 | ||||
-rw-r--r-- | server/src/routes/ui/error.rs | 7 | ||||
-rw-r--r-- | server/src/routes/ui/player.rs | 9 |
9 files changed, 165 insertions, 97 deletions
@@ -127,9 +127,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.71" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" [[package]] name = "argon2" @@ -256,7 +256,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] @@ -273,7 +273,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] @@ -484,7 +484,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] @@ -631,7 +631,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] @@ -650,7 +650,7 @@ name = "ebml_derive" version = "0.1.0" dependencies = [ "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] @@ -1173,6 +1173,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] +name = "jellyclient" +version = "0.1.0" +dependencies = [ + "anyhow", + "jellycommon", + "log", + "reqwest", + "serde_json", +] + +[[package]] name = "jellycommon" version = "0.1.0" dependencies = [ @@ -1216,13 +1227,13 @@ dependencies = [ "chashmap", "chrono", "env_logger", + "jellyclient", "jellycommon", "jellyremuxer", "log", "markup", "once_cell", "rand 0.8.5", - "reqwest", "rocket", "serde", "serde_json", @@ -1297,9 +1308,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.18" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" dependencies = [ "value-bag", ] @@ -1489,7 +1500,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] @@ -1632,7 +1643,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] @@ -1658,7 +1669,7 @@ checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] @@ -1715,9 +1726,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.59" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] @@ -1730,7 +1741,7 @@ checksum = "606c4ba35817e2922a308af55ad51bab3645b59eae5c570d4a6cf07e36bd493b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", "version_check", "yansi", ] @@ -1846,7 +1857,7 @@ checksum = "8d2275aab483050ab2a7364c1a46604865ee7d6906684e08db0f090acf74f9e7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] @@ -1969,7 +1980,7 @@ dependencies = [ "proc-macro2", "quote", "rocket_http", - "syn 2.0.18", + "syn 2.0.28", "unicode-xid", ] @@ -2072,29 +2083,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.164" +version = "1.0.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +checksum = "0ea67f183f058fe88a4e3ec6e2788e003840893b91bac4559cabedd00863b3ed" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.164" +version = "1.0.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +checksum = "24e744d7782b686ab3b73267ef05697159cc0e5abbed3f47f9933165e5219036" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] name = "serde_json" -version = "1.0.96" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" dependencies = [ "itoa", "ryu", @@ -2256,9 +2267,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" dependencies = [ "proc-macro2", "quote", @@ -2304,7 +2315,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] @@ -2396,7 +2407,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] @@ -2494,7 +2505,7 @@ checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] @@ -2713,7 +2724,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", "wasm-bindgen-shared", ] @@ -2747,7 +2758,7 @@ checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1,3 +1,11 @@ [workspace] -members = ["server", "remuxer", "common", "tools", "matroska", "ebml_derive"] +members = [ + "server", + "remuxer", + "common", + "tools", + "matroska", + "ebml_derive", + "client", +] resolver = "2" diff --git a/client/Cargo.toml b/client/Cargo.toml new file mode 100644 index 0000000..a2bed77 --- /dev/null +++ b/client/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "jellyclient" +version = "0.1.0" +edition = "2021" + +[dependencies] +jellycommon = { path = "../common" } +log = "0.4.19" +reqwest = "0.11.18" +anyhow = "1.0.72" +serde_json = "1.0.104" diff --git a/client/src/lib.rs b/client/src/lib.rs new file mode 100644 index 0000000..a4d0b01 --- /dev/null +++ b/client/src/lib.rs @@ -0,0 +1,70 @@ +use reqwest::Client; +use serde_json::json; +use std::time::Duration; + +pub struct Instance { + pub host: String, + pub tls: bool, +} +pub struct Session(pub String); + +impl Instance { + pub fn base(&self) -> String { + format!( + "{}://{}", + if self.tls { "https" } else { "http" }, + self.host + ) + } +} +impl Session { + pub fn session_param(&self) -> String { + format!("session={}", self.0) + } +} + +pub fn stream( + instance: &Instance, + session: &Session, + id: &str, + tracks: &[usize], + webm: bool, +) -> String { + format!( + "{}/n/{}/stream?tracks={}&webm={}&{}", + instance.base(), + id, + tracks + .iter() + .map(|v| format!("{v}")) + .collect::<Vec<_>>() + .join(","), + if webm { "1" } else { "0" }, + session.session_param() + ) +} + +pub async fn login( + instance: &Instance, + username: String, + password: String, + expire: Duration, +) -> anyhow::Result<Session> { + let p = serde_json::to_string(&json!({ + "expire": expire.as_secs(), + "password": password, + "username": username, + })) + .unwrap(); + + let r = Client::builder() + .build()? + .post(format!("{}/api/account/login", instance.base())) + .body(p) + .send() + .await? + .json() + .await?; + + Ok(Session(r)) +} diff --git a/server/Cargo.toml b/server/Cargo.toml index 4617a18..487c4fc 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] jellycommon = { path = "../common" } jellyremuxer = { path = "../remuxer" } +jellyclient = { path = "../client" } serde = { version = "1.0.163", features = ["derive"] } bincode = { version = "2.0.0-rc.3", features = ["serde", "derive"] } @@ -29,7 +30,6 @@ tokio-util = { version = "0.7.8", features = ["io", "io-util"] } markup = "0.13.1" rocket = { version = "0.5.0-rc.3", features = ["secrets", "json"] } -reqwest = "0.11.18" sled = "0.34.7" typed-sled = "0.2.3" diff --git a/server/src/routes/api/mod.rs b/server/src/routes/api/mod.rs index 84dd6a8..b39950c 100644 --- a/server/src/routes/api/mod.rs +++ b/server/src/routes/api/mod.rs @@ -9,7 +9,6 @@ use super::ui::{ error::MyResult, }; use crate::database::Database; -use reqwest::Client; use rocket::{get, post, response::Redirect, serde::json::Json, State}; use serde_json::{json, Value}; @@ -28,26 +27,3 @@ pub fn r_api_account_login(database: &State<Database>, data: Json<LoginForm>) -> let token = login_logic(database, &data.username, &data.password)?; Ok(json!(token)) } -pub async fn c_api_account_login( - host: &str, - tls: bool, - username: String, - password: String, - expire: u64, -) -> MyResult<String> { - Ok(Client::builder() - .build()? - .post(format!( - "{}://{host}/api/account/login", - if tls { "https" } else { "http" } - )) - .body(serde_json::to_string(&LoginForm { - expire, - password, - username, - })?) - .send() - .await? - .json() - .await?) -} diff --git a/server/src/routes/stream.rs b/server/src/routes/stream.rs index 19a3f09..1277646 100644 --- a/server/src/routes/stream.rs +++ b/server/src/routes/stream.rs @@ -4,7 +4,7 @@ Copyright (C) 2023 metamuffin <metamuffin.org> */ use super::ui::{account::session::Session, error::MyError}; -use crate::{database::Database, routes::api::c_api_account_login, uri, CONF}; +use crate::{database::Database, CONF}; use anyhow::{anyhow, Result}; use jellycommon::MediaSource; use jellyremuxer::RemuxerContext; @@ -16,23 +16,13 @@ use rocket::{ response::{self, Redirect, Responder}, Either, Request, Response, State, }; -use std::ops::{Deref, Range}; +use std::{ + ops::{Deref, Range}, + time::Duration, +}; use tokio::io::{duplex, DuplexStream}; use tokio_util::io::SyncIoBridge; -pub fn stream_uri(id: &str, tracks: &[u64], webm: bool) -> String { - format!( - "/n/{}/stream?tracks={}&webm={}", - id, - tracks - .iter() - .map(|v| format!("{v}")) - .collect::<Vec<_>>() - .join(","), - if webm { "1" } else { "0" } - ) -} - #[get("/n/<id>/stream?<tracks>&<webm>")] pub async fn r_stream( _sess: Session, @@ -49,6 +39,11 @@ pub async fn r_stream( .source .ok_or(anyhow!("item does not contain media"))?; + let tracks = tracks + .split(',') + .map(|e| e.parse().map_err(|_| anyhow!("invalid number"))) + .collect::<Result<Vec<_>, _>>()?; + let source_tracks = match source { MediaSource::Local { tracks } => tracks, MediaSource::Remote { host, remote_id } => { @@ -56,15 +51,22 @@ pub async fn r_stream( .remote_credentials .get(&host) .ok_or(anyhow!("no credentials on the server-side"))?; - let token = - c_api_account_login(&host, false, username.to_owned(), password.to_owned(), 60) - .await?; - let uri = format!( - "{}://{host}{}&session={}", - if *tls { "https" } else { "http" }, - uri!(r_stream(remote_id, tracks, webm)), - token + let instance = jellyclient::Instance { host, tls: *tls }; + let session = jellyclient::login( + &instance, + username.to_owned(), + password.to_owned(), + Duration::from_secs(60), + ) + .await?; + + let uri = jellyclient::stream( + &instance, + &session, + &remote_id, + &tracks, + webm.unwrap_or(false), ); return Ok(Either::Right(Redirect::found(uri))); } @@ -79,13 +81,7 @@ pub async fn r_stream( ); let (a, b) = duplex(4096); - let remuxer = remuxer.deref().clone(); - let tracks = tracks - .split(',') - .map(|e| e.parse().map_err(|_| anyhow!("invalid number"))) - .collect::<Result<Vec<_>, _>>()?; - let b = SyncIoBridge::new(b); let urange = match &range { diff --git a/server/src/routes/ui/error.rs b/server/src/routes/ui/error.rs index d911a41..01aebd3 100644 --- a/server/src/routes/ui/error.rs +++ b/server/src/routes/ui/error.rs @@ -90,9 +90,4 @@ impl From<serde_json::Error> for MyError { fn from(err: serde_json::Error) -> Self { MyError(anyhow::anyhow!("{err}")) } -} -impl From<reqwest::Error> for MyError { - fn from(err: reqwest::Error) -> Self { - MyError(anyhow::anyhow!("{err}")) - } -} +}
\ No newline at end of file diff --git a/server/src/routes/ui/player.rs b/server/src/routes/ui/player.rs index 2af9d9e..e295b02 100644 --- a/server/src/routes/ui/player.rs +++ b/server/src/routes/ui/player.rs @@ -7,7 +7,7 @@ use super::{account::session::Session, layout::LayoutPage}; use crate::{ database::Database, routes::{ - stream::stream_uri, + stream::rocket_uri_macro_r_stream, ui::{ assets::{rocket_uri_macro_r_item_assets, AssetRole}, error::MyResult, @@ -21,7 +21,6 @@ use jellycommon::{Node, SourceTrackKind}; use markup::DynRender; use rocket::{get, FromForm, State}; - #[derive(FromForm, Default, Clone, Debug)] pub struct PlayerConfig { pub a: Option<u64>, @@ -47,7 +46,9 @@ pub fn r_player( .chain(conf.v.into_iter()) .chain(conf.a.into_iter()) .chain(conf.s.into_iter()) - .collect::<Vec<_>>(); + .map(|e| format!("{e}")) + .collect::<Vec<_>>() + .join(","); let conf = player_conf(item.clone(), !tracks.is_empty())?; Ok(LayoutPage { @@ -57,7 +58,7 @@ pub fn r_player( @if tracks.is_empty() { img.backdrop[src=uri!(r_item_assets(&id, AssetRole::Backdrop)).to_string()]; } else { - video[src=stream_uri(&id, &tracks, true), controls]{} + video[src=uri!(r_stream(&id, &tracks, Some(true))), controls]{} } @conf }, |