/* 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) 2023 metamuffin */ use anyhow::Result; use jellycommon::NodePublic; use reqwest::{ header::{HeaderMap, HeaderValue}, Client, }; use serde_json::json; use std::{io::Write, time::Duration}; #[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, username: String, password: String, expire: Duration, ) -> anyhow::Result { let session_token = Client::builder() .build()? .post(format!("{}/api/create_session", self.base())) .json(&json!({ "expire": expire.as_secs(), "password": password, "username": username, })) .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, } impl Session { fn session_param(&self) -> String { format!("session={}", self.session_token) } pub async fn node(&self, id: &str) -> Result { Ok(self .client .get(format!("{}/n/{id}", self.instance.base())) .send() .await? .json() .await?) } // TODO use AssetRole instead of str pub async fn node_asset(&self, id: &str, role: &str, mut writer: impl Write) -> Result<()> { let mut r = self .client .get(format!("{}/n/{id}/asset?role={role}", self.instance.base())) .send() .await?; while let Some(chunk) = r.chunk().await? { writer.write_all(&chunk)?; } Ok(()) } pub fn stream(&self, id: &str, tracks: &[usize], webm: bool) -> String { format!( "{}/n/{}/stream?tracks={}&webm={}&{}", self.instance.base(), id, tracks .iter() .map(|v| format!("{v}")) .collect::>() .join(","), if webm { "1" } else { "0" }, self.session_param() ) } }