358 lines
9.3 KiB
Rust
358 lines
9.3 KiB
Rust
pub mod locale;
|
|
mod ordering;
|
|
mod paginator;
|
|
pub mod stream_filter;
|
|
|
|
pub use locale::{Country, Language};
|
|
pub use paginator::Paginator;
|
|
|
|
use std::ops::Range;
|
|
|
|
use chrono::{DateTime, Local};
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
/*
|
|
#PLAYER
|
|
*/
|
|
|
|
pub trait FileFormat {
|
|
fn extension(&self) -> &str;
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
pub struct VideoPlayer {
|
|
pub details: VideoPlayerDetails,
|
|
pub video_streams: Vec<VideoStream>,
|
|
pub video_only_streams: Vec<VideoStream>,
|
|
pub audio_streams: Vec<AudioStream>,
|
|
pub subtitles: Vec<Subtitle>,
|
|
pub expires_in_seconds: u32,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
|
pub struct VideoPlayerDetails {
|
|
pub id: String,
|
|
pub title: String,
|
|
pub description: Option<String>,
|
|
pub length: u32,
|
|
pub thumbnails: Vec<Thumbnail>,
|
|
pub channel: ChannelId,
|
|
pub publish_date: Option<DateTime<Local>>,
|
|
pub view_count: u64,
|
|
pub keywords: Vec<String>,
|
|
pub category: Option<String>,
|
|
pub is_live_content: bool,
|
|
pub is_family_safe: Option<bool>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
|
pub struct VideoStream {
|
|
pub url: String,
|
|
pub itag: u32,
|
|
pub bitrate: u32,
|
|
pub average_bitrate: u32,
|
|
pub size: Option<u64>,
|
|
pub index_range: Option<Range<u32>>,
|
|
pub init_range: Option<Range<u32>>,
|
|
pub width: u32,
|
|
pub height: u32,
|
|
pub fps: u8,
|
|
pub quality: String,
|
|
pub hdr: bool,
|
|
pub mime: String,
|
|
pub format: VideoFormat,
|
|
pub codec: VideoCodec,
|
|
pub throttled: bool,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
|
pub struct AudioStream {
|
|
pub url: String,
|
|
pub itag: u32,
|
|
pub bitrate: u32,
|
|
pub average_bitrate: u32,
|
|
pub size: u64,
|
|
pub index_range: Option<Range<u32>>,
|
|
pub init_range: Option<Range<u32>>,
|
|
pub mime: String,
|
|
pub format: AudioFormat,
|
|
pub codec: AudioCodec,
|
|
pub throttled: bool,
|
|
pub track: Option<AudioTrack>,
|
|
}
|
|
|
|
#[derive(
|
|
Default, Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash,
|
|
)]
|
|
#[serde(rename_all = "snake_case")]
|
|
#[non_exhaustive]
|
|
pub enum VideoCodec {
|
|
#[default]
|
|
Unknown,
|
|
/// MPEG-4 Part 14 <https://en.wikipedia.org/wiki/MPEG-4_Part_14>
|
|
Mp4v,
|
|
/// avc1 aka H.264: <https://en.wikipedia.org/wiki/Advanced_Video_Coding>
|
|
Avc1,
|
|
/// VP9: <https://en.wikipedia.org/wiki/VP9>
|
|
Vp9,
|
|
/// AV1, the latest codec: <https://en.wikipedia.org/wiki/AV1>
|
|
Av01,
|
|
}
|
|
|
|
#[derive(
|
|
Default, Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash,
|
|
)]
|
|
#[serde(rename_all = "snake_case")]
|
|
#[non_exhaustive]
|
|
pub enum AudioCodec {
|
|
#[default]
|
|
Unknown,
|
|
/// MP4A aka AAC: <https://en.wikipedia.org/wiki/Advanced_Audio_Coding>
|
|
Mp4a,
|
|
/// Opus: <https://en.wikipedia.org/wiki/Opus_(audio_format)>
|
|
Opus,
|
|
}
|
|
|
|
/// The video file format
|
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
#[serde(rename_all = "snake_case")]
|
|
#[non_exhaustive]
|
|
pub enum VideoFormat {
|
|
#[serde(rename = "3gp")]
|
|
ThreeGp,
|
|
Mp4,
|
|
Webm,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
|
pub struct AudioTrack {
|
|
pub id: String,
|
|
pub lang: Option<String>,
|
|
pub lang_name: String,
|
|
pub is_default: bool,
|
|
}
|
|
|
|
impl FileFormat for VideoFormat {
|
|
fn extension(&self) -> &str {
|
|
match self {
|
|
VideoFormat::ThreeGp => ".3gp",
|
|
VideoFormat::Mp4 => ".mp4",
|
|
VideoFormat::Webm => ".webm",
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
#[serde(rename_all = "snake_case")]
|
|
#[non_exhaustive]
|
|
pub enum AudioFormat {
|
|
M4a,
|
|
Webm,
|
|
}
|
|
|
|
impl FileFormat for AudioFormat {
|
|
fn extension(&self) -> &str {
|
|
match self {
|
|
AudioFormat::M4a => ".m4a",
|
|
AudioFormat::Webm => ".webm",
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
|
pub struct Thumbnail {
|
|
pub url: String,
|
|
pub width: u32,
|
|
pub height: u32,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
|
pub struct Subtitle {
|
|
pub url: String,
|
|
pub lang: String,
|
|
pub lang_name: String,
|
|
pub auto_generated: bool,
|
|
}
|
|
|
|
/*
|
|
#PLAYLIST
|
|
*/
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
pub struct Playlist {
|
|
pub id: String,
|
|
pub name: String,
|
|
pub videos: Paginator<PlaylistVideo>,
|
|
pub video_count: u32,
|
|
pub thumbnail: Vec<Thumbnail>,
|
|
pub description: Option<String>,
|
|
pub channel: Option<ChannelId>,
|
|
pub last_update: Option<DateTime<Local>>,
|
|
pub last_update_txt: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
pub struct PlaylistVideo {
|
|
pub id: String,
|
|
pub title: String,
|
|
pub length: u32,
|
|
pub thumbnail: Vec<Thumbnail>,
|
|
pub channel: ChannelId,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
pub struct ChannelId {
|
|
pub id: String,
|
|
pub name: String,
|
|
}
|
|
|
|
/*
|
|
#VIDEO DETAILS
|
|
*/
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
pub struct VideoDetails {
|
|
/// Unique YouTube video ID
|
|
pub id: String,
|
|
/// Video title
|
|
pub title: String,
|
|
/// Video description
|
|
pub description: String,
|
|
/// Channel of the video
|
|
pub channel: Channel,
|
|
/// Number of views
|
|
pub view_count: u64,
|
|
/// Number of likes
|
|
///
|
|
/// `None` if the like count was hidden by the creator.
|
|
pub like_count: Option<u32>,
|
|
/// Video publishing date. Start date in case of a livestream.
|
|
///
|
|
/// `None` if the date could not be parsed.
|
|
pub publish_date: Option<DateTime<Local>>,
|
|
/// Textual video publishing date (e.g. `Aug 2, 2013`, depends on language)
|
|
pub publish_date_txt: String,
|
|
/// Is the video a livestream?
|
|
pub is_live: bool,
|
|
/// Is the video published under the Creative Commons BY 3.0 license?
|
|
///
|
|
/// Information about the license:
|
|
///
|
|
/// https://www.youtube.com/t/creative_commons
|
|
///
|
|
/// https://creativecommons.org/licenses/by/3.0/
|
|
pub is_ccommons: bool,
|
|
/// Recommended videos
|
|
///
|
|
/// Note: Recommendations are not available for age-restricted videos
|
|
pub recommended: Paginator<RecommendedVideo>,
|
|
/// Paginator to fetch comments (most liked first)
|
|
pub top_comments: Paginator<Comment>,
|
|
/// Paginator to fetch comments (latest first)
|
|
pub latest_comments: Paginator<Comment>,
|
|
}
|
|
|
|
/*
|
|
@RECOMMENDATIONS
|
|
*/
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
pub struct RecommendedVideo {
|
|
/// Unique YouTube video ID
|
|
pub id: String,
|
|
/// Video title
|
|
pub title: String,
|
|
/// Video length in seconds.
|
|
///
|
|
/// Is `None` for livestreams.
|
|
pub length: Option<u32>,
|
|
/// Video thumbnail
|
|
pub thumbnail: Vec<Thumbnail>,
|
|
/// Channel of the video
|
|
pub channel: Channel,
|
|
/// Video publishing date.
|
|
///
|
|
/// `None` if the date could not be parsed.
|
|
pub publish_date: Option<DateTime<Local>>,
|
|
/// Textual video publish date (e.g. `11 months ago`, depends on language)
|
|
///
|
|
/// Is `None` for livestreams.
|
|
pub publish_date_txt: Option<String>,
|
|
/// View count
|
|
///
|
|
/// Is `None` if it could not be parsed
|
|
pub view_count: Option<u64>,
|
|
/// Is the video an active livestream?
|
|
pub is_live: bool,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
pub struct Channel {
|
|
/// Unique YouTube channel ID
|
|
pub id: String,
|
|
/// Channel name
|
|
pub name: String,
|
|
/// Channel avatar/profile picture
|
|
pub avatar: Vec<Thumbnail>,
|
|
/// Channel verification mark
|
|
pub verification: Verification,
|
|
/// Approximate number of subscribers
|
|
///
|
|
/// Info: This is only present in the `VideoDetails` response
|
|
pub subscriber_count: Option<u32>,
|
|
/// Textual subscriber count (e.g `1.41M subscribers`, depends on language)
|
|
pub subscriber_count_txt: Option<String>,
|
|
}
|
|
|
|
/*
|
|
@COMMENTS
|
|
*/
|
|
|
|
#[derive(Default, Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
|
#[serde(rename_all = "snake_case")]
|
|
pub enum Verification {
|
|
#[default]
|
|
/// Unverified channel (default)
|
|
None,
|
|
/// Verified channel (✓ checkmark symbol)
|
|
Verified,
|
|
/// Verified music artist (♪ music note symbol)
|
|
Artist,
|
|
}
|
|
|
|
impl Verification {
|
|
pub fn verified(&self) -> bool {
|
|
self != &Self::None
|
|
}
|
|
}
|
|
|
|
// TODO: impl popularity comparison
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
pub struct Comment {
|
|
/// Unique YouTube Comment-ID (e.g. `UgynScMrsqGSL8qvePl4AaABAg`)
|
|
pub id: String,
|
|
/// Comment text
|
|
pub text: String,
|
|
/// Comment author
|
|
///
|
|
/// There may be comments with missing authors (possibly deleted users?).
|
|
pub author: Option<Channel>,
|
|
/// Comment publishing date.
|
|
///
|
|
/// `None` if the date could not be parsed.
|
|
pub publish_date: Option<DateTime<Local>>,
|
|
/// Textual comment publish date (e.g. `14 hours ago`), depends on language setting
|
|
pub publish_date_txt: String,
|
|
/// Number of comment likes
|
|
pub like_count: Option<u32>,
|
|
/// Number of replies
|
|
pub reply_count: u32,
|
|
/// Paginator to fetch comment replies
|
|
pub replies: Paginator<Comment>,
|
|
/// Is the comment from the channel owner?
|
|
pub by_owner: bool,
|
|
/// Has the channel owner pinned the comment to the top?
|
|
pub pinned: bool,
|
|
/// Has the channel owner marked the comment with a ❤️ heart ?
|
|
pub hearted: bool,
|
|
}
|