mirror of
https://github.com/OMGeeky/google_youtube.git
synced 2026-02-23 15:49:49 +01:00
use anyhow result in most cases & some more tracing improvements
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "google_youtube"
|
||||
version = "0.1.2"
|
||||
version = "0.1.3"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
@@ -18,7 +18,7 @@ serde_json = "1.0"
|
||||
|
||||
async-trait = "0.1.60"
|
||||
strfmt = "0.2.2"
|
||||
|
||||
anyhow = "1.0"
|
||||
log = "0.4"
|
||||
simplelog = "0.12.1"
|
||||
#[patch.crates-io.yup-oauth2]
|
||||
|
||||
121
src/lib.rs
121
src/lib.rs
@@ -1,7 +1,7 @@
|
||||
|
||||
use crate::prelude::*;
|
||||
use anyhow::{anyhow, Context};
|
||||
use std::default::Default;
|
||||
use std::error::Error;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use exponential_backoff::youtube::generic_check_backoff_youtube;
|
||||
@@ -20,17 +20,27 @@ use google_youtube3::{
|
||||
hyper::{Body, Response},
|
||||
hyper_rustls::HttpsConnector,
|
||||
};
|
||||
#[cfg(feature = "tracing")]
|
||||
use tracing::instrument;
|
||||
use youtube::YouTube;
|
||||
use youtube::{hyper, hyper_rustls::HttpsConnectorBuilder};
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
mod auth;
|
||||
pub mod scopes;
|
||||
pub mod prelude;
|
||||
pub mod scopes;
|
||||
// mod config;
|
||||
|
||||
pub struct YoutubeClient {
|
||||
pub client: YouTube<HttpsConnector<HttpConnector>>,
|
||||
}
|
||||
impl Debug for YoutubeClient {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("YoutubeClient").finish()
|
||||
}
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub enum PrivacyStatus {
|
||||
Public,
|
||||
Unlisted,
|
||||
@@ -46,11 +56,12 @@ impl PrivacyStatus {
|
||||
}
|
||||
}
|
||||
impl YoutubeClient {
|
||||
pub async fn new<S: Into<String>>(
|
||||
path_to_application_secret: Option<S>,
|
||||
scopes: Vec<S>,
|
||||
user: Option<S>,
|
||||
) -> Result<Self, Box<dyn Error>> {
|
||||
#[cfg_attr(feature = "tracing", instrument)]
|
||||
pub async fn new(
|
||||
path_to_application_secret: Option<impl Into<String> + Debug>,
|
||||
scopes: Vec<impl Into<String> + Debug>,
|
||||
user: Option<impl Into<String> + Debug>,
|
||||
) -> anyhow::Result<Self> {
|
||||
let scopes = scopes
|
||||
.into_iter()
|
||||
.map(|s| s.into())
|
||||
@@ -64,23 +75,29 @@ impl YoutubeClient {
|
||||
.build(),
|
||||
);
|
||||
|
||||
let path_to_application_secret = match path_to_application_secret {
|
||||
None => "auth/service_account2.json".to_string(),
|
||||
Some(s) => s.into(),
|
||||
};
|
||||
|
||||
let auth = auth::get_authenticator(path_to_application_secret, &scopes, user).await?;
|
||||
|
||||
let path_to_application_secret = path_to_application_secret
|
||||
.map(|x| x.into())
|
||||
.unwrap_or_else(|| {
|
||||
warn!("the path to the application secret was not provided. Using default!");
|
||||
"auth/service_account2.json".to_string()
|
||||
});
|
||||
trace!(
|
||||
"getting authenticator from path: {}",
|
||||
path_to_application_secret
|
||||
);
|
||||
let auth = auth::get_authenticator(path_to_application_secret, &scopes, user)
|
||||
.await
|
||||
.map_err(|e| anyhow!("error: {}", e))
|
||||
.context("could not get authenticator")?;
|
||||
trace!("creating youtube client");
|
||||
let client: YouTube<HttpsConnector<HttpConnector>> = YouTube::new(hyper_client, auth);
|
||||
|
||||
let res = Self { client };
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub async fn find_playlist_by_name(
|
||||
&self,
|
||||
name: &str,
|
||||
) -> Result<Option<Playlist>, Box<dyn Error>> {
|
||||
#[cfg_attr(feature = "tracing", instrument)]
|
||||
pub async fn find_playlist_by_name(&self, name: &str) -> Result<Option<Playlist>> {
|
||||
let part = vec!["snippet".to_string()];
|
||||
|
||||
struct PlaylistParams {
|
||||
@@ -100,7 +117,10 @@ impl YoutubeClient {
|
||||
}
|
||||
let para = PlaylistParams { part, mine: true };
|
||||
let (_res, playlists): (Response<Body>, PlaylistListResponse) =
|
||||
generic_check_backoff_youtube(&self.client, ¶, list_playlist).await??;
|
||||
generic_check_backoff_youtube(&self.client, ¶, list_playlist)
|
||||
.await
|
||||
.map_err(|e| anyhow!("backoff error: {}", e))?
|
||||
.context("list_playlist returned an error")?;
|
||||
|
||||
if let Some(items) = playlists.items {
|
||||
for element in items {
|
||||
@@ -116,10 +136,8 @@ impl YoutubeClient {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub async fn find_playlist_or_create_by_name(
|
||||
&self,
|
||||
name: &str,
|
||||
) -> Result<Playlist, Box<dyn Error>> {
|
||||
#[cfg_attr(feature = "tracing", instrument)]
|
||||
pub async fn find_playlist_or_create_by_name(&self, name: &str) -> Result<Playlist> {
|
||||
let playlist = self.find_playlist_by_name(name).await?;
|
||||
if let Some(playlist) = playlist {
|
||||
return Ok(playlist);
|
||||
@@ -128,11 +146,8 @@ impl YoutubeClient {
|
||||
Ok(playlist)
|
||||
}
|
||||
|
||||
pub async fn add_video_to_playlist(
|
||||
&self,
|
||||
video: &Video,
|
||||
playlist: &Playlist,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
#[cfg_attr(feature = "tracing", instrument)]
|
||||
pub async fn add_video_to_playlist(&self, video: &Video, playlist: &Playlist) -> Result<()> {
|
||||
let playlist_item = PlaylistItem {
|
||||
snippet: Some(PlaylistItemSnippet {
|
||||
playlist_id: Some(playlist.id.clone().unwrap()),
|
||||
@@ -160,22 +175,25 @@ impl YoutubeClient {
|
||||
|
||||
let (res, _) =
|
||||
generic_check_backoff_youtube(&self.client, &playlist_item, insert_playlist_item)
|
||||
.await??;
|
||||
.await
|
||||
.map_err(|e| anyhow!("backoff error: {}", e))?
|
||||
.context("insert playlist item returned an error")?;
|
||||
if res.status().is_success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!("got status: {}", res.status().as_u16()).into())
|
||||
Err(anyhow!("got status: {}", res.status().as_u16()))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn upload_video<S: Into<String>, V: Into<Vec<String>>>(
|
||||
#[cfg_attr(feature = "tracing", instrument)]
|
||||
pub async fn upload_video(
|
||||
&self,
|
||||
path: impl AsRef<Path>,
|
||||
title: S,
|
||||
description: S,
|
||||
tags: V,
|
||||
path: impl AsRef<Path> + Debug,
|
||||
title: impl Into<String> + Debug,
|
||||
description: impl Into<String> + Debug,
|
||||
tags: impl Into<Vec<String>> + Debug,
|
||||
privacy_status: PrivacyStatus,
|
||||
) -> Result<Video, Box<dyn Error>> {
|
||||
) -> Result<Video> {
|
||||
info!("test 123");
|
||||
let video = Video {
|
||||
snippet: Some(VideoSnippet {
|
||||
@@ -212,7 +230,10 @@ impl YoutubeClient {
|
||||
para: &UploadParameters,
|
||||
) -> Result<(Response<Body>, Video), google_youtube3::Error> {
|
||||
info!("Opening file: {:?}", para.path);
|
||||
let stream = std::fs::File::open(¶.path)?;
|
||||
let stream = std::fs::File::open(¶.path).map_err(|e| {
|
||||
error!("could not open file: {} error: {}", ¶.path.display(), e);
|
||||
e
|
||||
})?;
|
||||
info!("Uploading file: {:?}", para.path);
|
||||
|
||||
let insert_call = client.videos().insert(para.video.clone());
|
||||
@@ -220,14 +241,19 @@ impl YoutubeClient {
|
||||
let upload_call = insert_call.upload_resumable(stream, "video/mp4".parse().unwrap());
|
||||
// .upload(stream, "video/mp4".parse().unwrap());
|
||||
info!("Upload request");
|
||||
let res = upload_call.await;
|
||||
let res = upload_call.await.map_err(|e| {
|
||||
error!("upload call did not work: {}", e);
|
||||
e
|
||||
});
|
||||
info!("Upload request done");
|
||||
res
|
||||
}
|
||||
|
||||
info!("Starting upload...");
|
||||
let (response, video) =
|
||||
generic_check_backoff_youtube(&self.client, ¶ms, upload_fn).await??;
|
||||
let (response, video) = generic_check_backoff_youtube(&self.client, ¶ms, upload_fn)
|
||||
.await
|
||||
.map_err(|e| anyhow!("backoff error: {}", e))?
|
||||
.context("upload_fn returned an error")?;
|
||||
|
||||
// let (response, video) = exponential_backoff::youtube::check_backoff_youtube_upload(
|
||||
// &self.client,
|
||||
@@ -245,7 +271,7 @@ impl YoutubeClient {
|
||||
info!("Status: {}", response.status());
|
||||
info!("Body: {:?}", response);
|
||||
info!("Video: {:?}", video);
|
||||
Err(format!("got status: {}", response.status().as_u16()).into())
|
||||
Err(anyhow!("got status: {}", response.status().as_u16()))
|
||||
}
|
||||
|
||||
// return Ok(video);
|
||||
@@ -264,7 +290,8 @@ impl YoutubeClient {
|
||||
// }
|
||||
// }
|
||||
}
|
||||
async fn create_playlist(&self, name: &str) -> Result<Playlist, Box<dyn Error>> {
|
||||
#[cfg_attr(feature = "tracing", instrument)]
|
||||
async fn create_playlist(&self, name: &str) -> Result<Playlist> {
|
||||
let playlist = Playlist {
|
||||
snippet: Some(PlaylistSnippet {
|
||||
title: Some(name.to_string()),
|
||||
@@ -281,16 +308,20 @@ impl YoutubeClient {
|
||||
}
|
||||
|
||||
let (res, playlist) =
|
||||
generic_check_backoff_youtube(&self.client, &playlist, create_playlist).await??;
|
||||
generic_check_backoff_youtube(&self.client, &playlist, create_playlist)
|
||||
.await
|
||||
.map_err(|e| anyhow!("backoff error: {}", e))?
|
||||
.map_err(|e| anyhow!("create playlist returned an error: {}", e))?;
|
||||
|
||||
if res.status().is_success() {
|
||||
Ok(playlist)
|
||||
} else {
|
||||
Err(format!("got status: {}", res.status().as_u16()).into())
|
||||
Err(anyhow!("got status: {}", res.status().as_u16()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "tracing", instrument)]
|
||||
pub async fn sample() -> Result<(), Box<dyn Error>> {
|
||||
info!("Hello from the youtube lib!");
|
||||
Ok(())
|
||||
|
||||
@@ -2,3 +2,5 @@
|
||||
pub use log::{debug, error, info, trace, warn};
|
||||
#[cfg(feature = "tracing")]
|
||||
pub use tracing::{debug, error, info, trace, warn};
|
||||
|
||||
pub use anyhow::Result;
|
||||
|
||||
Reference in New Issue
Block a user