feat: add base jellyfin and ersatztv sdk
This commit is contained in:
commit
49cf01c668
11 changed files with 2184 additions and 0 deletions
19
src/config.rs
Normal file
19
src/config.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
use clap::{Parser, ValueEnum};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version, about)]
|
||||
pub struct Args {
|
||||
/// URL host of the ErsatzTv service
|
||||
pub host: String,
|
||||
/// UUID of the build
|
||||
pub build_id: Uuid,
|
||||
/// The playout build mode
|
||||
pub playout_mode: PlayoutMode,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug)]
|
||||
pub enum PlayoutMode {
|
||||
Continue,
|
||||
Reset,
|
||||
}
|
||||
42
src/ersatz_tv.rs
Normal file
42
src/ersatz_tv.rs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
use anyhow::anyhow;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::ersatz_tv::models::ContextModel;
|
||||
|
||||
pub mod models;
|
||||
|
||||
pub struct Client {
|
||||
_client: reqwest::Client,
|
||||
host: String,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub fn new(host: String) -> anyhow::Result<Self> {
|
||||
let _client = reqwest::Client::builder().gzip(true).build()?;
|
||||
Ok(Self { _client, host })
|
||||
}
|
||||
|
||||
pub async fn get_context(&self, build_id: Uuid) -> anyhow::Result<ContextModel> {
|
||||
let response = self
|
||||
._client
|
||||
.get(format!(
|
||||
"{}/api/scripted/playout/build/{}/context",
|
||||
self.host, build_id
|
||||
))
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
if let Err(err) = &response.error_for_status_ref() {
|
||||
return Err(anyhow!(
|
||||
"Request for {} returned with status {}:\n{}",
|
||||
err.url().unwrap().path(),
|
||||
err.status().unwrap_or_default(),
|
||||
response.text().await?
|
||||
));
|
||||
}
|
||||
|
||||
let context: ContextModel = response.json().await?;
|
||||
|
||||
Ok(context)
|
||||
}
|
||||
}
|
||||
10
src/ersatz_tv/models.rs
Normal file
10
src/ersatz_tv/models.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ContextModel {
|
||||
current_time: chrono::DateTime<chrono::Local>,
|
||||
start_time: chrono::DateTime<chrono::Local>,
|
||||
finish_time: chrono::DateTime<chrono::Local>,
|
||||
is_done: bool,
|
||||
}
|
||||
72
src/jellyfin.rs
Normal file
72
src/jellyfin.rs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
use anyhow::anyhow;
|
||||
use reqwest::header::{HeaderMap, HeaderValue};
|
||||
|
||||
use crate::jellyfin::models::GetItemsResponseModel;
|
||||
|
||||
pub mod models;
|
||||
|
||||
static JELLYFIN_VGM_FOLDER: &str = "";
|
||||
|
||||
pub struct Client {
|
||||
_client: reqwest::Client,
|
||||
host: String,
|
||||
user_id: String,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub fn new<T: Into<String>>(host: T) -> anyhow::Result<Self> {
|
||||
let mut headers = HeaderMap::new();
|
||||
let auth_str = format!(
|
||||
r#"MediaBrowser Client="Jellyfin Web", Device="Firefox", DeviceId="TW96aWxsYS81LjAgKFgxMTsgTGludXggeDg2XzY0OyBydjo5NC4wKSBHZWNrby8yMDEwMDEwMSBGaXJlZm94Lzk0LjB8MTYzODA1MzA2OTY4Mw11", Version="10.7.6", Token="{}""#,
|
||||
"e9d4caa8c94f429280b43ba45a50ba6b"
|
||||
);
|
||||
|
||||
headers.insert("Authorization", HeaderValue::from_str(auth_str.as_str())?);
|
||||
|
||||
headers.insert("Accept", HeaderValue::from_static("application/json"));
|
||||
|
||||
let _client = reqwest::Client::builder()
|
||||
.gzip(true)
|
||||
.default_headers(headers)
|
||||
.build()?;
|
||||
Ok(Self {
|
||||
_client,
|
||||
host: host.into(),
|
||||
user_id: String::from("4a80af8c258e417e98f86e870e17d929"),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn get_items<T: Into<String> + std::fmt::Display>(
|
||||
&self,
|
||||
parent_id: T,
|
||||
) -> anyhow::Result<GetItemsResponseModel> {
|
||||
// INFO: needs to be created manually, escaped characters mess with Jellyfin server
|
||||
let query = format!(
|
||||
"parentId={parent_id}&sort_by=SortName&fields=Path,RecursiveItemCount&enable_images=false"
|
||||
);
|
||||
|
||||
let response = self
|
||||
._client
|
||||
.get(format!(
|
||||
"{}/Users/{}/items?{}",
|
||||
self.host, self.user_id, query
|
||||
))
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
if let Err(err) = &response.error_for_status_ref() {
|
||||
return Err(anyhow!(
|
||||
"Request for {} returned with status {}:\n{}",
|
||||
err.url().unwrap().path(),
|
||||
err.status().unwrap_or_default(),
|
||||
response.text().await?
|
||||
));
|
||||
}
|
||||
|
||||
println!("{}", response.url());
|
||||
|
||||
let context: GetItemsResponseModel = response.json().await?;
|
||||
|
||||
Ok(context)
|
||||
}
|
||||
}
|
||||
50
src/jellyfin/models.rs
Normal file
50
src/jellyfin/models.rs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GetItemsQueryStringModel {
|
||||
pub parent_id: String,
|
||||
pub sort_by: String,
|
||||
pub fields: String,
|
||||
pub enable_images: bool,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct GetItemsResponseModel {
|
||||
pub items: Vec<ItemModel>,
|
||||
pub total_record_count: u64,
|
||||
pub start_index: u64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct ItemModel {
|
||||
pub name: String,
|
||||
pub id: String,
|
||||
pub path: String,
|
||||
pub production_year: Option<i64>,
|
||||
pub is_folder: bool,
|
||||
#[serde(rename = "Type")]
|
||||
pub type_field: String,
|
||||
pub artists: Option<Vec<String>>,
|
||||
pub artist_items: Option<Vec<ArtistItemModel>>,
|
||||
pub album_artist: Option<String>,
|
||||
pub album_artists: Option<Vec<AlbumArtistModel>>,
|
||||
pub media_type: String,
|
||||
pub recursive_item_count: u64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct ArtistItemModel {
|
||||
pub name: String,
|
||||
pub id: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct AlbumArtistModel {
|
||||
pub name: String,
|
||||
pub id: String,
|
||||
}
|
||||
3
src/lib.rs
Normal file
3
src/lib.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
pub mod config;
|
||||
pub mod ersatz_tv;
|
||||
pub mod jellyfin;
|
||||
19
src/main.rs
Normal file
19
src/main.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
use clap::Parser;
|
||||
use tv_scheduler::{config::Args, ersatz_tv, jellyfin};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
let args = Args::parse();
|
||||
// let tv = ersatz_tv::Client::new(args.host)?;
|
||||
|
||||
// let context = tv.get_context(args.build_id).await?;
|
||||
|
||||
// println!("{:?}", context);
|
||||
|
||||
let jelly = jellyfin::Client::new("https://media.hoshikusu.xyz")?;
|
||||
|
||||
let items = jelly.get_items("574563ff9a41f2c98c234db69157cc87").await?;
|
||||
println!("{:#?}", items);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue