use std::path::Path;
use crate::block_async;
#[cfg(feature = "live")]
use crate::blocking::stream::LiveStream;
use crate::blocking::stream::NonLiveStream;
use crate::constants::DEFAULT_DL_CHUNK_SIZE;
use crate::structs::{VideoError, VideoInfo, VideoOptions};
use crate::utils::choose_format;
use crate::Video as AsyncVideo;
#[cfg(feature = "live")]
use super::stream::LiveStreamOptions;
use super::stream::{NonLiveStreamOptions, Stream};
#[cfg(feature = "ffmpeg")]
use crate::structs::FFmpegArgs;
#[derive(Clone, Debug, derive_more::Display, PartialEq, Eq)]
pub struct Video(AsyncVideo);
impl Video {
pub fn new(url_or_id: impl Into<String>) -> Result<Self, VideoError> {
Ok(Self(AsyncVideo::new(url_or_id)?))
}
pub fn new_with_options(
url_or_id: impl Into<String>,
options: VideoOptions,
) -> Result<Self, VideoError> {
Ok(Self(AsyncVideo::new_with_options(url_or_id, options)?))
}
pub fn get_basic_info(&self) -> Result<VideoInfo, VideoError> {
Ok(block_async!(self.0.get_basic_info())?)
}
pub fn get_info(&self) -> Result<VideoInfo, VideoError> {
Ok(block_async!(self.0.get_info())?)
}
pub fn stream(&self) -> Result<Box<dyn Stream + Send + Sync>, VideoError> {
let client = self.0.get_client();
let options = self.0.get_options();
let info = block_async!(self.0.get_info())?;
let format = choose_format(&info.formats, &options)
.map_err(|_op| VideoError::VideoSourceNotFound)?;
let link = format.url;
if link.is_empty() {
return Err(VideoError::VideoSourceNotFound);
}
if format.is_hls {
#[cfg(feature = "live")]
{
let stream = LiveStream::new(LiveStreamOptions {
client: Some(client.clone()),
stream_url: link,
})?;
return Ok(Box::new(stream));
}
#[cfg(not(feature = "live"))]
{
return Err(VideoError::LiveStreamNotSupported);
}
}
let dl_chunk_size = options
.download_options
.dl_chunk_size
.unwrap_or(DEFAULT_DL_CHUNK_SIZE);
let start = 0;
let end = start + dl_chunk_size;
let mut content_length = format
.content_length
.unwrap_or("0".to_string())
.parse::<u64>()
.unwrap_or(0);
if content_length == 0 {
let content_length_response = block_async!(client.get(&link).send())
.map_err(VideoError::ReqwestMiddleware)?
.content_length()
.ok_or(VideoError::VideoNotFound)?;
content_length = content_length_response;
}
let stream = NonLiveStream::new(NonLiveStreamOptions {
client: Some(client.clone()),
link,
content_length,
dl_chunk_size,
start,
end,
#[cfg(feature = "ffmpeg")]
ffmpeg_args: None,
})?;
Ok(Box::new(stream))
}
#[cfg(feature = "ffmpeg")]
pub async fn stream_with_ffmpeg(
&self,
ffmpeg_args: Option<FFmpegArgs>,
) -> Result<Box<dyn Stream + Send + Sync>, VideoError> {
let client = self.0.get_client();
let options = self.0.get_options();
let info = block_async!(self.0.get_info())?;
let format = choose_format(&info.formats, &options)
.map_err(|_op| VideoError::VideoSourceNotFound)?;
let link = format.url;
if link.is_empty() {
return Err(VideoError::VideoSourceNotFound);
}
if format.is_hls {
#[cfg(feature = "live")]
{
let stream = LiveStream::new(LiveStreamOptions {
client: Some(client.clone()),
stream_url: link,
})?;
return Ok(Box::new(stream));
}
#[cfg(not(feature = "live"))]
{
return Err(VideoError::LiveStreamNotSupported);
}
}
let dl_chunk_size = options
.download_options
.dl_chunk_size
.unwrap_or(DEFAULT_DL_CHUNK_SIZE);
let start = 0;
let end = start + dl_chunk_size;
let mut content_length = format
.content_length
.unwrap_or("0".to_string())
.parse::<u64>()
.unwrap_or(0);
if content_length == 0 {
let content_length_response = client
.get(&link)
.send()
.await
.map_err(VideoError::ReqwestMiddleware)?
.content_length()
.ok_or(VideoError::VideoNotFound)?;
content_length = content_length_response;
}
let stream = NonLiveStream::new(NonLiveStreamOptions {
client: Some(client.clone()),
link,
content_length,
dl_chunk_size,
start,
end,
ffmpeg_args,
})?;
Ok(Box::new(stream))
}
pub fn download<P: AsRef<Path>>(&self, path: P) -> Result<(), VideoError> {
Ok(block_async!(self.0.download(path))?)
}
#[cfg(feature = "ffmpeg")]
pub async fn download_with_ffmpeg<P: AsRef<Path>>(
&self,
path: P,
ffmpeg_args: Option<FFmpegArgs>,
) -> Result<(), VideoError> {
Ok(block_async!(self
.0
.download_with_ffmpeg(path, ffmpeg_args))?)
}
pub fn get_video_url(&self) -> String {
self.0.get_video_url()
}
pub fn get_video_id(&self) -> String {
self.0.get_video_id()
}
}
impl std::ops::Deref for Video {
type Target = AsyncVideo;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::ops::DerefMut for Video {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}