diff options
Diffstat (limited to 'client')
-rw-r--r-- | client/Cargo.toml | 14 | ||||
-rw-r--r-- | client/src/lib.rs | 196 |
2 files changed, 0 insertions, 210 deletions
diff --git a/client/Cargo.toml b/client/Cargo.toml deleted file mode 100644 index 772de57..0000000 --- a/client/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "jellyclient" -version = "0.1.0" -edition = "2021" - -[dependencies] -jellycommon = { path = "../common" } -log = { workspace = true } -reqwest = { workspace = true } -anyhow = "1.0.95" -serde_json = "1.0.138" -serde = { version = "1.0.217", features = ["derive"] } -tokio = { workspace = true } -percent-encoding = "2.3.1" diff --git a/client/src/lib.rs b/client/src/lib.rs deleted file mode 100644 index d3172fd..0000000 --- a/client/src/lib.rs +++ /dev/null @@ -1,196 +0,0 @@ -/* - This file is part of jellything (https://codeberg.org/metamuffin/jellything) - which is licensed under the GNU Affero General Public License (version 3); see /COPYING. - Copyright (C) 2025 metamuffin <metamuffin.org> -*/ -use anyhow::Result; -use jellycommon::{ - api::{ApiHomeResponse, ApiNodeResponse, ApiSearchResponse}, - user::CreateSessionParams, -}; -use log::{debug, info}; -use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC}; -use reqwest::{ - header::{HeaderMap, HeaderValue}, - Client, -}; -use stream::StreamSpec; -use tokio::io::AsyncWriteExt; - -pub use jellycommon::*; - -#[derive(Debug, Clone)] -pub struct Instance { - pub host: String, - pub tls: bool, -} - -impl Instance { - pub fn new(host: String, tls: bool) -> Self { - Self { host, tls } - } - pub fn base(&self) -> String { - format!( - "{}://{}", - if self.tls { "https" } else { "http" }, - self.host - ) - } - pub async fn login(self, data: CreateSessionParams) -> anyhow::Result<Session> { - let session_token = Client::builder() - .build()? - .post(format!("{}/api/create_session", self.base())) - .json(&data) - .send() - .await? - .json() - .await?; - - let mut headers = HeaderMap::new(); - headers.insert( - "Cookie", - HeaderValue::from_str(&format!("session={session_token}")).unwrap(), - ); - headers.insert("Accept", HeaderValue::from_static("application/json")); - - Ok(Session { - instance: self, - session_token, - client: Client::builder().default_headers(headers).build().unwrap(), - }) - } -} - -pub struct Session { - client: Client, - instance: Instance, - session_token: String, -} - -pub trait UnpinWrite: tokio::io::AsyncWrite + std::marker::Unpin {} -impl<T: tokio::io::AsyncWrite + std::marker::Unpin> UnpinWrite for T {} - -impl Session { - fn session_param(&self) -> String { - format!("session={}", self.session_token) - } - - pub async fn node( - &self, - id: NodeIDOrSlug, - children: bool, - parents: bool, - ) -> Result<ApiNodeResponse> { - debug!("downloading node {id}"); - let params = match (children, parents) { - (true, true) => "?children&parents", - (true, false) => "?children", - (false, true) => "?parents", - (false, false) => "", - }; - Ok(self - .client - .get(format!("{}/n/{id}{params}", self.instance.base(),)) - .send() - .await? - .error_for_status()? - .json() - .await?) - } - - pub async fn search(&self, query: &str, page: usize) -> Result<ApiSearchResponse> { - debug!("searching for {query:?}"); - Ok(self - .client - .get(format!( - "{}/search?query={}&page={page}", - utf8_percent_encode(query, NON_ALPHANUMERIC), - self.instance.base(), - )) - .send() - .await? - .error_for_status()? - .json() - .await?) - } - - pub async fn home(&self) -> Result<ApiHomeResponse> { - debug!("home page"); - Ok(self - .client - .get(format!("{}/home", self.instance.base(),)) - .send() - .await? - .error_for_status()? - .json() - .await?) - } - - pub async fn node_thumbnail( - &self, - writer: impl UnpinWrite, - id: NodeIDOrSlug, - width: usize, - time: f64, - ) -> Result<()> { - debug!("downloading thumbnail for {id} at {time}s"); - self.download_url( - writer, - format!( - "{}/n/{id}/thumbnail?t={time}&width={width}", - self.instance.base(), - ), - ) - .await - } - - pub async fn asset(&self, writer: impl UnpinWrite, token: &str, width: usize) -> Result<()> { - debug!("downloading asset {token:?} (w={width})"); - self.download_url( - writer, - format!("{}/asset/{token}?width={width}", self.instance.base()), - ) - .await - } - - pub async fn stream( - &self, - writer: impl UnpinWrite, - id: NodeIDOrSlug, - stream_spec: &StreamSpec, - ) -> Result<()> { - self.download_url(writer, self.stream_url(id, stream_spec)) - .await - } - - pub fn stream_url(&self, id: NodeIDOrSlug, stream_spec: &StreamSpec) -> String { - format!( - "{}/n/{}/stream{}&{}", - self.instance.base(), - id, - stream_spec.to_query(), - self.session_param() - ) - } - - pub async fn download_url(&self, mut writer: impl UnpinWrite, url: String) -> Result<()> { - let mut r = self.client.get(url).send().await?.error_for_status()?; - while let Some(chunk) = r.chunk().await? { - writer.write_all(&chunk).await?; - } - Ok(()) - } - - pub async fn reimport(&self, incremental: bool) -> Result<()> { - info!("reimport"); - self.client - .post(format!( - "{}/admin/import?incremental={incremental}", - self.instance.base() - )) - .send() - .await?; - info!("done"); - Ok(()) - } -} |