use tmp file struct instead of paths and manual file deletion

This commit is contained in:
mykola2312 2024-03-30 05:11:46 +02:00
parent 9cc888258f
commit a85e36f1f2
4 changed files with 47 additions and 56 deletions

View file

@ -3,12 +3,11 @@ use teloxide::types::InputFile;
use tracing::{event, Level};
use super::types::HandlerResult;
use crate::dl::delete_if_exists;
use crate::dl::download;
async fn bot_download(bot: Bot, msg: Message, url: String) -> HandlerResult {
let output_path = match download(url.as_str()).await {
Ok(path) => path,
let output = match download(url.as_str()).await {
Ok(file) => file,
Err(e) => {
event!(Level::ERROR, "{}", e.to_string());
bot.send_message(msg.chat.id, e.to_string()).await?;
@ -16,14 +15,8 @@ async fn bot_download(bot: Bot, msg: Message, url: String) -> HandlerResult {
}
};
if let Err(e) = bot
.send_video(msg.chat.id, InputFile::file(&output_path))
.await
{
delete_if_exists(&output_path);
return Err(Box::new(e));
}
bot.send_video(msg.chat.id, InputFile::file(&output.path))
.await?;
Ok(())
}

View file

@ -5,6 +5,7 @@ use tracing::{event, Level};
use crate::dl::ffmpeg::FFMpeg;
use self::spawn::SpawnError;
use self::tmpfile::{TmpFile, TmpFileError};
use self::yt_dlp::{YtDlp, YtDlpError, YtDlpFormat, YtDlpInfo};
pub mod ffmpeg;
@ -30,6 +31,14 @@ impl From<YtDlpError> for DownloadError {
}
}
impl From<TmpFileError> for DownloadError {
fn from(value: TmpFileError) -> Self {
match value {
TmpFileError::MakePathError => DownloadError::MakePathError,
}
}
}
impl fmt::Display for DownloadError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use DownloadError as DE;
@ -76,7 +85,7 @@ pub fn delete_if_exists(path: &str) {
}
}
async fn download_fallback(url: &str, info: YtDlpInfo) -> Result<String, DownloadError> {
async fn download_fallback(url: &str, info: YtDlpInfo) -> Result<TmpFile, DownloadError> {
let av = match info.best_av_format() {
Some(av) => av,
None => {
@ -95,16 +104,10 @@ async fn download_fallback(url: &str, info: YtDlpInfo) -> Result<String, Downloa
}
};
let output_path = make_download_path(&info, None, &av)?;
if let Err(e) = YtDlp::download(url, &av.format_id, output_path.as_str()).await {
delete_if_exists(&output_path);
return Err(DownloadError::Message(e.to_string()));
}
Ok(output_path)
Ok(YtDlp::download(url, &info, &av).await?)
}
pub async fn download(url: &str) -> Result<String, DownloadError> {
pub async fn download(url: &str) -> Result<TmpFile, DownloadError> {
event!(Level::INFO, "url {}", url);
let info = YtDlp::load_info(url).await?;
@ -117,19 +120,8 @@ pub async fn download(url: &str) -> Result<String, DownloadError> {
None => return download_fallback(url, info).await,
};
// TODO: I should wrap those temp files in a impl Drop for defer deletion
let video_path = make_download_path(&info, Some("video"), &vf)?;
if let Err(e) = YtDlp::download(url, &vf.format_id, video_path.as_str()).await {
delete_if_exists(&video_path);
return Err(DownloadError::Message(e.to_string()));
}
let audio_path = make_download_path(&info, Some("audio"), &af)?;
if let Err(e) = YtDlp::download(url, &af.format_id, audio_path.as_str()).await {
delete_if_exists(&video_path);
delete_if_exists(&audio_path);
return Err(DownloadError::Message(e.to_string()));
}
let video = YtDlp::download(url, &info, &vf).await?;
let audio = YtDlp::download(url, &info, &af).await?;
let abr = if let Some(abr) = af.abr {
FFMpeg::round_mp3_bitrate(abr)
@ -144,8 +136,7 @@ pub async fn download(url: &str) -> Result<String, DownloadError> {
192
};
let output_path = make_download_path(&info, None, &vf)?;
let output = TmpFile::new(format!("{}.{}", &info.id, &vf.ext).as_str())?;
event!(
Level::INFO,
"for {} we joining video {} and audio {}",
@ -154,18 +145,10 @@ pub async fn download(url: &str) -> Result<String, DownloadError> {
af.format_id
);
let res = FFMpeg::join_video_audio(
video_path.as_str(),
audio_path.as_str(),
abr,
output_path.as_str(),
)
.await;
delete_if_exists(&video_path);
delete_if_exists(&audio_path);
let res = FFMpeg::join_video_audio(&video.path, &audio.path, abr, &output.path).await;
match res {
Ok(()) => Ok(output_path),
Ok(()) => Ok(output),
Err(e) => Err(DownloadError::Message(e.to_string())),
}
}

View file

@ -2,7 +2,7 @@ use std::fs;
use tracing::{event, Level};
pub enum TmpFileError {
MakePathError
MakePathError,
}
pub struct TmpFile {
@ -10,20 +10,20 @@ pub struct TmpFile {
}
impl TmpFile {
pub fn new(filename: String) -> Result<Self, TmpFileError> {
pub fn new(filename: &str) -> Result<Self, TmpFileError> {
let path = std::env::temp_dir()
.join(filename)
.into_os_string()
.into_string()
.map_err(|_| TmpFileError::MakePathError)?;
Ok(Self { path })
}
pub fn exists(&self) -> bool {
match fs::metadata(&self.path) {
Ok(_) => true,
Err(_) => false
Err(_) => false,
}
}
@ -41,4 +41,4 @@ impl Drop for TmpFile {
fn drop(&mut self) {
self.delete_if_exists();
}
}
}

View file

@ -200,6 +200,7 @@ pub enum YtDlpError {
ErrorMessage(String), // keep it separate type if we ever plan to parse yt-dlp errors
JsonError,
NoFormats,
MakePathError,
NoFilePresent,
}
// ^(?:ERROR: \[.*\] \S* )(.*$) - regex for matching yt-dlp's youtube errors
@ -213,6 +214,12 @@ impl From<SpawnError> for YtDlpError {
}
}
impl From<TmpFileError> for YtDlpError {
fn from(_value: TmpFileError) -> Self {
Self::MakePathError
}
}
impl From<serde_json::Error> for YtDlpError {
fn from(_value: serde_json::Error) -> Self {
Self::JsonError
@ -227,6 +234,7 @@ impl fmt::Display for YtDlpError {
YTE::ErrorMessage(msg) => write!(f, "yt-dlp error - {}", msg),
YTE::JsonError => write!(f, "json parsing error"),
YTE::NoFormats => write!(f, "no formats were parsed"),
YTE::MakePathError => write!(f, "make path error"),
YTE::NoFilePresent => write!(f, "downloaded file doesn't exists"),
}
}
@ -247,7 +255,14 @@ impl YtDlp {
Ok(info)
}
pub async fn download(url: &str, format_id: &str, output_path: &str) -> Result<(), YtDlpError> {
pub async fn download(
url: &str,
info: &YtDlpInfo,
format: &YtDlpFormat,
) -> Result<TmpFile, YtDlpError> {
let file =
TmpFile::new(format!("{}_{}.{}", info.id, format.format_id, format.ext).as_str())?;
spawn(
"python",
&[
@ -255,17 +270,17 @@ impl YtDlp {
"yt_dlp",
url,
"-f",
format_id,
&format.format_id,
"-o",
output_path,
&file.path,
"--force-overwrites",
],
)
.await?;
match fs::metadata(output_path) {
Ok(_) => Ok(()),
Err(_) => Err(YtDlpError::NoFilePresent),
match file.exists() {
true => Ok(file),
false => Err(YtDlpError::NoFilePresent),
}
}
}