383 lines
13 KiB
Rust
383 lines
13 KiB
Rust
use std::collections::HashMap;
|
|
|
|
use crate::util::requester::Requester;
|
|
|
|
#[derive(serde::Serialize, serde::Deserialize, Debug)]
|
|
pub struct VideosRequest {
|
|
//"versionInstallDate":"2025-06-03T18:20:20Z","languageCode":"en","appInstallDate":"2025-06-03T18:20:20Z","server":"spacemoehre","sexu
|
|
pub clientHash: Option<String>, // "a07b23c9b07813c65050e2a4041ca777",
|
|
pub blockedKeywords: Option<String>, // "kittens",
|
|
pub countryCode: Option<String>, // "DE",
|
|
pub clientVersion: Option<String>, // "2.1.4-22b",
|
|
pub timestamp: Option<String>, // "1748976686",
|
|
pub blockedUploaders: Option<String>, // "",
|
|
pub anonId: Option<String>, // "1AB8A060-A47D-47EF-B9CB-63980ED84C8A",
|
|
pub debugTools: Option<bool>, // false,
|
|
pub versionInstallDate: Option<String>, // "2025-06-03T18:20:20Z",
|
|
pub languageCode: Option<String>, // "en",
|
|
pub appInstallDate: Option<String>, // "2025-06-03T18:20:20Z",
|
|
pub server: Option<String>, // "spacemoehre",
|
|
pub sexuality: Option<String>, // "straight",
|
|
pub channel: Option<String>, //"youtube",
|
|
pub sort: Option<String>, //"new",
|
|
pub query: Option<String>, //"kittens",
|
|
pub page: Option<String>, //1,
|
|
pub perPage: Option<String>, //10,
|
|
// Your server's global options will be sent in the videos request
|
|
// pub flavor: "mint chocolate chip"
|
|
pub featured: Option<String>, // "featured",
|
|
pub category: Option<String>, // "pmv"
|
|
pub sites: Option<String>, //
|
|
pub filter: Option<String>, //
|
|
pub language: Option<String>, //
|
|
pub networks: Option<String>, //
|
|
pub stars: Option<String>, //
|
|
pub categories: Option<String>,
|
|
pub duration: Option<String>,
|
|
}
|
|
|
|
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
|
pub struct ServerOptions {
|
|
pub featured: Option<String>, // "featured",
|
|
pub category: Option<String>, // "pmv"
|
|
pub sites: Option<String>, //
|
|
pub filter: Option<String>,
|
|
pub language: Option<String>, // "en"
|
|
pub requester: Option<Requester>,
|
|
pub network: Option<String>, //
|
|
pub stars: Option<String>, //
|
|
pub categories: Option<String>, //
|
|
pub duration: Option<String>, //
|
|
pub sort: Option<String>, //
|
|
}
|
|
|
|
#[derive(serde::Serialize, Debug)]
|
|
pub struct PageInfo {
|
|
pub hasNextPage: bool, // true,
|
|
pub resultsPerPage: u32, // 10
|
|
}
|
|
|
|
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
|
pub struct VideoEmbed {
|
|
pub html: String,
|
|
pub source: String,
|
|
}
|
|
impl VideoEmbed {
|
|
pub fn new(html: String, source: String) -> Self {
|
|
VideoEmbed { html, source }
|
|
}
|
|
}
|
|
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
|
pub struct VideoItem {
|
|
pub duration: u32, // 110,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub views: Option<u32>, // 14622653,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub rating: Option<f32>, // 0.0,
|
|
pub id: String, // "c85017ca87477168d648727753c4ded8a35f173e22ef93743e707b296becb299",
|
|
pub title: String, // "20 Minutes of Adorable Kittens BEST Compilation",
|
|
pub url: String, // "https://www.youtube.com/watch?v=y0sF5xhGreA",
|
|
pub channel: String, // "youtube",
|
|
pub thumb: String, // "https://i.ytimg.com/vi/y0sF5xhGreA/hqdefault.jpg",
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub uploader: Option<String>, // "The Pet Collective",
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub uploaderUrl: Option<String>, // "https://www.youtube.com/@petcollective",
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub verified: Option<bool>, // false,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub tags: Option<Vec<String>>, // [],
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub uploadedAt: Option<u64>, // 1741142954
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub formats: Option<Vec<VideoFormat>>, // Additional HTTP headers if needed
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub embed: Option<VideoEmbed>, // Optional embed information
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub preview: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub aspectRatio: Option<f32>,
|
|
}
|
|
#[allow(dead_code)]
|
|
impl VideoItem {
|
|
pub fn new(
|
|
id: String,
|
|
title: String,
|
|
url: String,
|
|
channel: String,
|
|
thumb: String,
|
|
duration: u32,
|
|
) -> Self {
|
|
VideoItem {
|
|
duration: duration, // Placeholder, adjust as needed
|
|
views: None, // Placeholder, adjust as needed
|
|
rating: None, // Placeholder, adjust as needed
|
|
id,
|
|
title,
|
|
url,
|
|
channel,
|
|
thumb,
|
|
uploader: None,
|
|
uploaderUrl: None,
|
|
verified: None,
|
|
tags: None, // Placeholder, adjust as needed
|
|
uploadedAt: None,
|
|
formats: None, // Placeholder for formats
|
|
embed: None, // Placeholder for embed information
|
|
preview: None,
|
|
aspectRatio: None,
|
|
}
|
|
}
|
|
pub fn tags(mut self, tags: Vec<String>) -> Self {
|
|
if tags.is_empty(){
|
|
return self;
|
|
}
|
|
self.tags = Some(tags);
|
|
self
|
|
}
|
|
pub fn uploader(mut self, uploader: String) -> Self {
|
|
self.uploader = Some(uploader);
|
|
self
|
|
}
|
|
pub fn uploader_url(mut self, uploader_url: String) -> Self {
|
|
self.uploaderUrl = Some(uploader_url);
|
|
self
|
|
}
|
|
pub fn verified(mut self, verified: bool) -> Self {
|
|
self.verified = Some(verified);
|
|
self
|
|
}
|
|
pub fn views(mut self, views: u32) -> Self {
|
|
self.views = Some(views);
|
|
self
|
|
}
|
|
pub fn rating(mut self, rating: f32) -> Self {
|
|
self.rating = Some(rating);
|
|
self
|
|
}
|
|
pub fn uploaded_at(mut self, uploaded_at: u64) -> Self {
|
|
self.uploadedAt = Some(uploaded_at);
|
|
self
|
|
}
|
|
pub fn formats(mut self, formats: Vec<VideoFormat>) -> Self {
|
|
if formats.is_empty(){
|
|
return self;
|
|
}
|
|
self.formats = Some(formats);
|
|
self
|
|
}
|
|
pub fn add_format(mut self, format: VideoFormat) {
|
|
if let Some(formats) = self.formats.as_mut() {
|
|
formats.push(format);
|
|
} else {
|
|
self.formats = Some(vec![format]);
|
|
}
|
|
}
|
|
pub fn embed(mut self, embed: VideoEmbed) -> Self {
|
|
self.embed = Some(embed);
|
|
self
|
|
}
|
|
pub fn preview(mut self, preview: String) -> Self {
|
|
self.preview = Some(preview);
|
|
self
|
|
}
|
|
|
|
pub fn aspect_ratio(mut self, aspect_ratio: f32) -> Self {
|
|
self.aspectRatio = Some(aspect_ratio);
|
|
self
|
|
}
|
|
}
|
|
|
|
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
|
pub struct VideoFormat {
|
|
pub url: String,
|
|
quality: String,
|
|
format: String,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
format_id: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
format_note: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
filesize: Option<u32>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
asr: Option<u32>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
fps: Option<u32>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
width: Option<u32>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
height: Option<u32>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
tbr: Option<u32>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
language: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
language_preference: Option<u32>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
ext: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
vcodec: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
acodec: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
dynamic_range: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
abr: Option<u32>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
vbr: Option<u32>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
container: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
protocol: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
audio_ext: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
video_ext: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
resolution: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
http_headers: Option<HashMap<String, String>>,
|
|
}
|
|
impl VideoFormat {
|
|
pub fn new(url: String, quality: String, format: String) -> Self {
|
|
let _ = format;
|
|
VideoFormat {
|
|
url,
|
|
quality,
|
|
format: format, // Default format
|
|
format_id: Some("mp4-1080".to_string()),
|
|
format_note: None,
|
|
filesize: None,
|
|
asr: None,
|
|
fps: None,
|
|
width: None,
|
|
height: None,
|
|
tbr: None,
|
|
language: None,
|
|
language_preference: None,
|
|
ext: Some("mp4".to_string()),
|
|
vcodec: None,
|
|
acodec: None,
|
|
dynamic_range: None,
|
|
abr: None,
|
|
vbr: None,
|
|
container: None,
|
|
protocol: Some("m3u8_native".to_string()),
|
|
audio_ext: Some("none".to_string()),
|
|
video_ext: Some("mp4".to_string()),
|
|
resolution: None,
|
|
http_headers: None,
|
|
}
|
|
}
|
|
pub fn add_http_header(&mut self, key: String, value: String) {
|
|
if self.http_headers.is_none() {
|
|
self.http_headers = Some(HashMap::new());
|
|
}
|
|
if let Some(headers) = &mut self.http_headers {
|
|
headers.insert(key, value);
|
|
}
|
|
}
|
|
pub fn http_header(&mut self, key: String, value: String) -> Self {
|
|
if self.http_headers.is_none() {
|
|
self.http_headers = Some(HashMap::new());
|
|
}
|
|
if let Some(headers) = &mut self.http_headers {
|
|
headers.insert(key, value);
|
|
}
|
|
self.to_owned()
|
|
}
|
|
pub fn format_id(mut self, format_id: String) -> Self {
|
|
self.format_id = Some(format_id);
|
|
self
|
|
}
|
|
pub fn format_note(mut self, format_note: String) -> Self {
|
|
self.format_note = Some(format_note);
|
|
self
|
|
}
|
|
// pub fn filesize(mut self, filesize: u32) -> Self {
|
|
// self.filesize = Some(filesize);
|
|
// self
|
|
// }
|
|
// pub fn asr(mut self, asr: u32) -> Self {
|
|
// self.asr = Some(asr);
|
|
// self
|
|
// }
|
|
// pub fn fps(mut self, fps: u32) -> Self {
|
|
// self.fps = Some(fps);
|
|
// self
|
|
// }
|
|
// pub fn width(mut self, width: u32) -> Self {
|
|
// self.width = Some(width);
|
|
// self
|
|
// }
|
|
// pub fn height(mut self, height: u32) -> Self {
|
|
// self.height = Some(height);
|
|
// self
|
|
// }
|
|
// pub fn tbr(mut self, tbr: u32) -> Self {
|
|
// self.tbr = Some(tbr);
|
|
// self
|
|
// }
|
|
// pub fn language(mut self, language: String) -> Self {
|
|
// self.language = Some(language);
|
|
// self
|
|
// }
|
|
// pub fn language_preference(mut self, language_preference: u32) -> Self {
|
|
// self.language_preference = Some(language_preference);
|
|
// self
|
|
// }
|
|
// pub fn ext(mut self, ext: String) -> Self {
|
|
// self.ext = Some(ext);
|
|
// self
|
|
// }
|
|
// pub fn vcodec(mut self, vcodec: String) -> Self {
|
|
// self.vcodec = Some(vcodec);
|
|
// self
|
|
// }
|
|
// pub fn acodec(mut self, acodec: String) -> Self {
|
|
// self.acodec = Some(acodec);
|
|
// self
|
|
// }
|
|
// pub fn dynamic_range(mut self, dynamic_range: String) -> Self {
|
|
// self.dynamic_range = Some(dynamic_range);
|
|
// self
|
|
// }
|
|
// pub fn abr(mut self, abr: u32) -> Self {
|
|
// self.abr = Some(abr);
|
|
// self
|
|
// }
|
|
// pub fn vbr(mut self, vbr: u32) -> Self {
|
|
// self.vbr = Some(vbr);
|
|
// self
|
|
// }
|
|
// pub fn container(mut self, container: String) -> Self {
|
|
// self.container = Some(container);
|
|
// self
|
|
// }
|
|
// pub fn protocol(mut self, protocol: String) -> Self {
|
|
// self.protocol = Some(protocol);
|
|
// self
|
|
// }
|
|
// pub fn audio_ext(mut self, audio_ext: String) -> Self {
|
|
// self.audio_ext = Some(audio_ext);
|
|
// self
|
|
// }
|
|
// pub fn video_ext(mut self, video_ext: String) -> Self {
|
|
// self.video_ext = Some(video_ext);
|
|
// self
|
|
// }
|
|
// pub fn resolution(mut self, resolution: String) -> Self {
|
|
// self.resolution = Some(resolution);
|
|
// self
|
|
// }
|
|
// pub fn http_headers(mut self, http_headers: HashMap<String, String>) -> Self {
|
|
// self.http_headers = Some(http_headers);
|
|
// self
|
|
// }
|
|
}
|
|
#[derive(serde::Serialize, Debug)]
|
|
pub struct Videos {
|
|
pub pageInfo: PageInfo,
|
|
pub items: Vec<VideoItem>,
|
|
}
|