feat: add URL resolver
This commit is contained in:
parent
2b70badd4e
commit
b22f6995cc
22 changed files with 673 additions and 279 deletions
|
|
@ -11,6 +11,8 @@ use std::ops::Range;
|
|||
use chrono::{DateTime, Local, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{error::Error, util};
|
||||
|
||||
use self::richtext::RichText;
|
||||
|
||||
/*
|
||||
|
|
@ -26,6 +28,64 @@ pub struct Thumbnail {
|
|||
pub height: u32,
|
||||
}
|
||||
|
||||
/// Entities extracted from a YouTube URL
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub enum UrlTarget {
|
||||
Video { id: String, start_time: u32 },
|
||||
Channel { id: String },
|
||||
Playlist { id: String },
|
||||
}
|
||||
|
||||
impl ToString for UrlTarget {
|
||||
fn to_string(&self) -> String {
|
||||
self.to_url()
|
||||
}
|
||||
}
|
||||
|
||||
impl UrlTarget {
|
||||
pub fn to_url(&self) -> String {
|
||||
self.to_url_yt_host("https://www.youtube.com")
|
||||
}
|
||||
|
||||
pub fn to_url_yt_host(&self, yt_host: &str) -> String {
|
||||
match self {
|
||||
UrlTarget::Video { id, start_time, .. } => match start_time {
|
||||
0 => format!("{}/watch?v={}", yt_host, id),
|
||||
n => format!("{}/watch?v={}&t={}s", yt_host, id, n),
|
||||
},
|
||||
UrlTarget::Channel { id } => {
|
||||
format!("{}/channel/{}", yt_host, id)
|
||||
}
|
||||
UrlTarget::Playlist { id } => {
|
||||
format!("{}/playlist?list={}", yt_host, id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn validate(&self) -> Result<(), Error> {
|
||||
match self {
|
||||
UrlTarget::Video { id, .. } => {
|
||||
match util::VIDEO_ID_REGEX.is_match(id).unwrap_or_default() {
|
||||
true => Ok(()),
|
||||
false => Err(Error::Other("invalid video id".into())),
|
||||
}
|
||||
}
|
||||
UrlTarget::Channel { id } => {
|
||||
match util::CHANNEL_ID_REGEX.is_match(id).unwrap_or_default() {
|
||||
true => Ok(()),
|
||||
false => Err(Error::Other("invalid channel id".into())),
|
||||
}
|
||||
}
|
||||
UrlTarget::Playlist { id } => {
|
||||
match util::PLAYLIST_ID_REGEX.is_match(id).unwrap_or_default() {
|
||||
true => Ok(()),
|
||||
false => Err(Error::Other("invalid playlist id".into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#PLAYER
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::UrlTarget;
|
||||
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[non_exhaustive]
|
||||
pub struct RichText(pub Vec<TextComponent>);
|
||||
|
|
@ -13,20 +15,8 @@ pub enum TextComponent {
|
|||
Text(String),
|
||||
/// Web link
|
||||
Web { text: String, url: String },
|
||||
/// Link to a YouTube video
|
||||
Video {
|
||||
text: String,
|
||||
id: String,
|
||||
start_time: u32,
|
||||
},
|
||||
/// Link to a YouTube channel
|
||||
Channel { text: String, id: String },
|
||||
/// Link to a YouTube playlist
|
||||
Playlist { text: String, id: String },
|
||||
/// Link to a YouTube Music artist
|
||||
Artist { text: String, id: String },
|
||||
/// Link to a YouTube Music album
|
||||
Album { text: String, id: String },
|
||||
/// Link to a YouTube entity
|
||||
YouTube { text: String, target: UrlTarget },
|
||||
}
|
||||
|
||||
/// Trait for converting rich text to plain text.
|
||||
|
|
@ -60,11 +50,7 @@ impl TextComponent {
|
|||
match self {
|
||||
TextComponent::Text(text) => text,
|
||||
TextComponent::Web { text, .. } => text,
|
||||
TextComponent::Video { text, .. } => text,
|
||||
TextComponent::Channel { text, .. } => text,
|
||||
TextComponent::Playlist { text, .. } => text,
|
||||
TextComponent::Artist { text, .. } => text,
|
||||
TextComponent::Album { text, .. } => text,
|
||||
TextComponent::YouTube { text, .. } => text,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -72,16 +58,7 @@ impl TextComponent {
|
|||
match self {
|
||||
TextComponent::Text(_) => "".to_owned(),
|
||||
TextComponent::Web { url, .. } => url.to_owned(),
|
||||
TextComponent::Video { id, start_time, .. } => match start_time {
|
||||
0 => format!("{}/watch?v={}", yt_host, id),
|
||||
n => format!("{}/watch?v={}&t={}s", yt_host, id, n),
|
||||
},
|
||||
TextComponent::Channel { id, .. } | TextComponent::Artist { id, .. } => {
|
||||
format!("{}/channel/{}", yt_host, id)
|
||||
}
|
||||
TextComponent::Playlist { id, .. } | TextComponent::Album { id, .. } => {
|
||||
format!("{}/playlist?list={}", yt_host, id)
|
||||
}
|
||||
TextComponent::YouTube { target, .. } => target.to_url_yt_host(yt_host),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Reference in a new issue