use serde::{Deserialize, Serialize};
use std::borrow::Cow;
use crate::Error;
#[derive(PartialEq, Debug, Clone, Deserialize)]
pub struct SearchSuggestion {
pub runs: Vec<TextRun>,
pub suggestion_type: SuggestionType,
}
#[derive(PartialEq, Debug, Clone, Deserialize, Copy)]
pub enum SuggestionType {
History,
Prediction,
}
#[derive(PartialEq, Debug, Clone, Deserialize)]
pub enum TextRun {
Bold(String),
Normal(String),
}
impl TextRun {
pub fn take_text(self) -> String {
match self {
TextRun::Bold(s) => s,
TextRun::Normal(s) => s,
}
}
pub fn get_text(&self) -> &str {
match self {
TextRun::Bold(s) => s,
TextRun::Normal(s) => s,
}
}
}
impl SearchSuggestion {
pub fn get_text(&self) -> String {
self.runs
.iter()
.fold(String::new(), |acc, r| acc + &r.get_text())
}
pub(crate) fn new(suggestion_type: SuggestionType, runs: Vec<TextRun>) -> Self {
Self {
runs,
suggestion_type,
}
}
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
pub struct Thumbnail {
pub height: u64,
pub width: u64,
pub url: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Explicit {
IsExplicit,
NotExplicit,
}
#[derive(Debug)]
pub struct Album {
pub title: String,
pub playlist_id: Option<String>,
pub browse_id: AlbumID<'static>,
pub category: Option<String>, pub thumbnails: Vec<Thumbnail>,
pub year: Option<String>,
}
pub trait YoutubeID<'a> {
fn get_raw(&self) -> &str;
fn from_raw<S: Into<Cow<'a, str>>>(raw_str: S) -> Self;
}
pub trait BrowseID<'a>: YoutubeID<'a> {}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum AlbumType {
Single,
Album,
EP,
}
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub struct BrowseParams<'a>(Cow<'a, str>);
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub struct PlaylistID<'a>(Cow<'a, str>);
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub struct AlbumID<'a>(Cow<'a, str>);
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub struct ChannelID<'a>(Cow<'a, str>);
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub struct ProfileID<'a>(Cow<'a, str>);
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub struct PodcastID<'a>(Cow<'a, str>);
#[derive(PartialEq, Debug, Clone, Default, Serialize, Deserialize)]
pub struct VideoID<'a>(Cow<'a, str>);
#[derive(PartialEq, Debug, Clone, Default, Serialize, Deserialize)]
pub struct LyricsID<'a>(pub Cow<'a, str>);
impl<'a> YoutubeID<'a> for AlbumID<'a> {
fn get_raw(&self) -> &str {
&self.0
}
fn from_raw<S: Into<Cow<'a, str>>>(raw_str: S) -> Self {
Self(raw_str.into())
}
}
impl<'a> YoutubeID<'a> for ProfileID<'a> {
fn get_raw(&self) -> &str {
&self.0
}
fn from_raw<S: Into<Cow<'a, str>>>(raw_str: S) -> Self {
Self(raw_str.into())
}
}
impl<'a> YoutubeID<'a> for PodcastID<'a> {
fn get_raw(&self) -> &str {
&self.0
}
fn from_raw<S: Into<Cow<'a, str>>>(raw_str: S) -> Self {
Self(raw_str.into())
}
}
impl<'a> YoutubeID<'a> for VideoID<'a> {
fn get_raw(&self) -> &str {
&self.0
}
fn from_raw<S: Into<Cow<'a, str>>>(raw_str: S) -> Self {
Self(raw_str.into())
}
}
impl<'a> BrowseID<'a> for PlaylistID<'a> {}
impl<'a> YoutubeID<'a> for PlaylistID<'a> {
fn get_raw(&self) -> &str {
&self.0
}
fn from_raw<S: Into<Cow<'a, str>>>(raw_str: S) -> Self {
Self(raw_str.into())
}
}
impl<'a> BrowseID<'a> for ChannelID<'a> {}
impl<'a> YoutubeID<'a> for ChannelID<'a> {
fn get_raw(&self) -> &str {
&self.0
}
fn from_raw<S: Into<Cow<'a, str>>>(raw_str: S) -> Self {
Self(raw_str.into())
}
}
impl<'a> From<&'a AlbumID<'a>> for AlbumID<'a> {
fn from(value: &'a AlbumID<'a>) -> Self {
let core = &value.0;
AlbumID(core.as_ref().into())
}
}
impl<'a> BrowseParams<'a> {
pub fn from_raw<S>(raw_str: S) -> BrowseParams<'a>
where
S: Into<Cow<'a, str>>,
{
Self(raw_str.into())
}
pub fn get_raw(&self) -> &str {
&self.0
}
}
impl AlbumType {
pub fn try_from_str<S: AsRef<str>>(value: S) -> Result<Self, crate::Error> {
match value.as_ref() {
"Album" => Ok(AlbumType::Album),
"EP" => Ok(AlbumType::EP),
"Single" => Ok(AlbumType::Single),
x => Err(Error::other(format!("Error parsing AlbumType from {x}"))),
}
}
}
pub mod watch {
use serde::Deserialize;
use super::{LyricsID, PlaylistID};
#[derive(PartialEq, Debug, Clone, Deserialize)]
pub struct WatchPlaylist {
pub _tracks: Vec<()>,
pub playlist_id: Option<PlaylistID<'static>>,
pub lyrics_id: LyricsID<'static>,
}
impl WatchPlaylist {
pub fn new(playlist_id: Option<PlaylistID<'static>>, lyrics_id: LyricsID<'static>) -> Self {
Self {
playlist_id,
lyrics_id,
_tracks: Default::default(),
}
}
}
}
pub mod library {
use crate::{ChannelID, Thumbnail};
use serde::{Deserialize, Serialize};
use super::PlaylistID;
#[derive(PartialEq, Debug, Clone, Deserialize, Serialize)]
pub struct Playlist {
pub playlist_id: PlaylistID<'static>,
pub title: String,
pub thumbnails: Vec<Thumbnail>,
pub count: Option<usize>,
pub description: Option<String>,
pub author: Option<String>,
}
#[derive(PartialEq, Debug, Clone, Deserialize, Serialize)]
pub struct LibraryArtist {
pub channel_id: ChannelID<'static>,
pub artist: String,
pub byline: String, }
}
pub mod browsing {
use serde::Deserialize;
#[derive(PartialEq, Debug, Clone, Deserialize)]
pub struct Lyrics {
pub lyrics: String,
pub source: String,
}
impl Lyrics {
pub fn get_lyrics(&self) -> &str {
self.lyrics.as_str()
}
pub fn get_source(&self) -> &str {
self.source.as_str()
}
pub fn new(lyrics: String, source: String) -> Self {
Self { lyrics, source }
}
}
}
pub mod youtuberesult {
use crate::{ChannelID, Thumbnail};
use super::PlaylistID;
pub trait YoutubeResult {
fn get_core(&self) -> &ResultCore;
fn get_set_video_id(&self) -> &Option<String> {
&self.get_core().set_video_id
}
fn get_duration(&self) -> &Option<String> {
&self.get_core().duration
}
fn get_feedback_tok_add(&self) -> &Option<String> {
&self.get_core().feedback_tok_add
}
fn get_feedback_tok_rem(&self) -> &Option<String> {
&self.get_core().feedback_tok_rem
}
fn get_title(&self) -> &String {
&self.get_core().title
}
fn get_like_status(&self) -> &Option<String> {
&self.get_core().like_status
}
fn get_thumbnails(&self) -> &Vec<Thumbnail> {
&self.get_core().thumbnails
}
fn get_is_available(&self) -> &bool {
&self.get_core().is_available
}
fn get_is_explicit(&self) -> &bool {
&self.get_core().is_explicit
}
fn get_video_type(&self) -> &Option<String> {
&self.get_core().video_type
}
fn get_channel_id(&self) -> &Option<ChannelID> {
&self.get_core().browse_id
}
fn get_playlist_id(&self) -> &Option<PlaylistID> {
&self.get_core().playlist_id
}
fn get_playlist_subtitle(&self) -> &Option<String> {
&self.get_core().playlist_subtitle
}
}
#[derive(Debug, Clone)]
pub struct ResultCore {
set_video_id: Option<String>,
duration: Option<String>,
feedback_tok_add: Option<String>,
feedback_tok_rem: Option<String>,
title: String,
like_status: Option<String>,
thumbnails: Vec<super::Thumbnail>,
is_available: bool,
is_explicit: bool,
video_type: Option<String>,
browse_id: Option<ChannelID<'static>>,
playlist_id: Option<PlaylistID<'static>>,
playlist_subtitle: Option<String>, }
impl ResultCore {
pub fn new(
set_video_id: Option<String>,
duration: Option<String>,
feedback_tok_add: Option<String>,
feedback_tok_rem: Option<String>,
title: String,
like_status: Option<String>,
thumbnails: Vec<super::Thumbnail>,
is_available: bool,
is_explicit: bool,
video_type: Option<String>,
browse_id: Option<ChannelID<'static>>,
playlist_id: Option<PlaylistID<'static>>,
playlist_subtitle: Option<String>,
) -> Self {
Self {
set_video_id,
duration,
feedback_tok_add,
feedback_tok_rem,
title,
like_status,
thumbnails,
is_available,
is_explicit,
video_type,
browse_id,
playlist_id,
playlist_subtitle,
}
}
}
}