This commit is contained in:
OMGeeky
2024-06-04 20:58:33 +02:00
parent 0af60f727c
commit 060cf10744
6 changed files with 34 additions and 71 deletions

View File

@@ -9,7 +9,7 @@ use std::collections::HashMap;
use std::ffi::OsStr;
use std::path::{Path, PathBuf};
use tracing::instrument;
use twba_local_db::entities::video_upload::{UploadStatus};
use twba_local_db::entities::video_upload::UploadStatus;
use twba_local_db::prelude::*;
use twba_local_db::re_exports::sea_orm::{
ActiveModelTrait, ActiveValue, ColumnTrait, DatabaseConnection, EntityTrait, IntoActiveModel,
@@ -26,8 +26,7 @@ lazy_static! {
#[derive(Debug)]
pub struct UploaderClient {
db: DatabaseConnection,
reqwest_client: reqwest::Client,
youtube_client: HashMap<String, youtube::YoutubeClient>,
youtube_clients: HashMap<String, youtube::YoutubeClient>,
}
impl UploaderClient {
@@ -42,7 +41,7 @@ impl UploaderClient {
let count = videos.len();
info!("got {} videos to upload", count);
'video_loop: for video in videos {
for video in videos {
match self.upload_video(&video).await {
Ok(_) => {
info!("Uploaded video: {}: {}", video.id, video.name);
@@ -50,27 +49,22 @@ impl UploaderClient {
Err(e) => {
error!("Error while uploading the video: {}: {}", video.id, e);
{
let fail_count = video.fail_count + 1;
let previous_fails = video
.fail_reason
.as_ref()
.unwrap_or(&String::new())
.to_string();
let mut video = video.clone().into_active_model();
video.fail_count = ActiveValue::Set(fail_count);
video.fail_reason = ActiveValue::Set(Some(format!(
"{}: {}\n\n{}",
fail_count, e, previous_fails
)));
}
// self.set_video_status_on_db(&video, Status::UploadFailed)
// .await?;
let fail_count = video.fail_count + 1;
let previous_fails = video
.fail_reason
.as_ref()
.unwrap_or(&String::new())
.to_string();
let mut video = video.clone().into_active_model();
video.fail_count = ActiveValue::Set(fail_count);
video.fail_reason = ActiveValue::Set(Some(format!(
"{}: {}\n\n{}",
fail_count, e, previous_fails
)));
}
}
}
//todo: maybe add some log to the db when videos were last uploaded?
Ok(())
}
@@ -86,7 +80,6 @@ impl UploaderClient {
let part_count = video.part_count;
let parts_folder_path = Path::new(&CONF.download_folder_path).join(video_id.to_string());
let parts = get_part_files(&parts_folder_path, part_count).await?;
dbg!(&parts);
let user = Users::find_by_id(video.user_id)
.one(&self.db)
.await?
@@ -96,9 +89,7 @@ impl UploaderClient {
let all_parts_data = VideoData {
video_tags: tags,
video_category: 22,
//TODO get from config
video_privacy: VideoStatusPrivacyStatusEnum::Private,
//TODO get from config
playlist_privacy: PlaylistStatusPrivacyStatusEnum::Private,
playlist_description: create_youtube_description(video, &user, Location::Playlist)?,
playlist_title: create_youtube_title(video, &user, Location::Playlist)?,
@@ -111,7 +102,7 @@ impl UploaderClient {
self.set_playlist_id_for_video(video, playlist_id.clone())
.await?;
'part_loop: for (part, part_number) in parts {
for (part, part_number) in parts {
let mut video_upload = self
.insert_video_upload(video_id, part_number)
.await?
@@ -133,9 +124,7 @@ impl UploaderClient {
video.id,
part.display()
);
let upload = client_for_video
.upload_video_part(video, &part, part_number, data)
.await;
let upload = client_for_video.upload_video_part(&part, data).await;
match upload {
Ok(uploaded_video_id) => {
info!("uploaded part: {}", part.display());
@@ -145,7 +134,7 @@ impl UploaderClient {
.await?;
video_upload.upload_status = ActiveValue::Set(UploadStatus::Uploaded);
video_upload.youtube_video_id = ActiveValue::Set(Some(uploaded_video_id));
video_upload = video_upload.update(&self.db).await?.into_active_model();
video_upload.update(&self.db).await?;
}
Err(e) => {
error!("could not upload part: {}", e);
@@ -223,7 +212,7 @@ impl UploaderClient {
}
fn get_client_for_video(&self, video: &VideosModel) -> Result<&youtube::YoutubeClient> {
let c = self
.youtube_client
.youtube_clients
.get(&video.user_id.to_string())
.ok_or(UploaderError::NoClient(video.user_id))?;
Ok(c)
@@ -248,7 +237,10 @@ async fn get_part_files(folder_path: &Path, count: i32) -> Result<Vec<(PathBuf,
parts.push((path, part_number));
}
if parts.len() != count as usize {
return Err(UploaderError::PartCountMismatch(count as usize, parts.len()));
return Err(UploaderError::PartCountMismatch(
count as usize,
parts.len(),
));
}
parts.sort_by_key(|a| a.1);
Ok(parts)
@@ -280,8 +272,6 @@ fn get_part_number_from_path(path: &Path) -> Result<usize> {
impl UploaderClient {
pub async fn new(db: DatabaseConnection) -> Result<Self> {
let reqwest_client = reqwest::Client::new();
let mut clients = HashMap::new();
let users = twba_local_db::get_watched_users(&db).await?;
@@ -298,8 +288,7 @@ impl UploaderClient {
Ok(Self {
db,
reqwest_client,
youtube_client: clients,
youtube_clients: clients,
})
}
}

View File

@@ -14,7 +14,7 @@ use std::fmt::{Debug, Formatter};
use std::path::{Path, PathBuf};
use tokio::fs;
use tracing::instrument;
use twba_local_db::prelude::{UsersModel, VideosModel};
use twba_local_db::prelude::UsersModel;
mod auth;
pub(crate) mod data;
@@ -23,18 +23,11 @@ mod flow_delegate;
pub struct YoutubeClient {
//TODO: change this to a thing that does exponential backoff when possible
client: google_youtube3::YouTube<HttpsConnector<HttpConnector>>,
user: Option<UsersModel>,
}
impl YoutubeClient {
#[instrument(skip(self, video, path, data))]
pub(crate) async fn upload_video_part(
&self,
video: &VideosModel,
path: &Path,
part_num: usize,
data: VideoData,
) -> Result<String> {
#[instrument(skip(self, path, data))]
pub(crate) async fn upload_video_part(&self, path: &Path, data: VideoData) -> Result<String> {
let video_data = data;
let upload_result = self
.upload_youtube_video_resumable(video_data, path)
@@ -134,14 +127,7 @@ impl YoutubeClient {
..Default::default()
};
let playlist_insert_call = self.client.playlists().insert(playlist);
let (x, playlist) = playlist_insert_call
.doit()
.await
// .context("could not create playlist")
// ?
.unwrap()
//test
;
let (_, playlist) = playlist_insert_call.doit().await.unwrap();
playlist.id.ok_or(UploaderError::NoIdReturned)
}
@@ -170,7 +156,7 @@ impl YoutubeClient {
)
.await?;
let client = google_youtube3::YouTube::new(hyper_client, auth);
Ok(Self { client, user })
Ok(Self { client })
}
fn create_hyper_client() -> Client<HttpsConnector<HttpConnector>> {

View File

@@ -2,12 +2,12 @@ use crate::client::youtube::flow_delegate::CustomFlowDelegate;
use crate::errors::{AuthError, PersistentPathError};
use crate::prelude::*;
use google_youtube3::api::Scope;
use google_youtube3::oauth2::authenticator::Authenticator;
use google_youtube3::{hyper::client::HttpConnector, hyper_rustls::HttpsConnector, oauth2};
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use tokio::fs;
use tracing::instrument;
use google_youtube3::oauth2::authenticator::Authenticator;
type Result<T> = std::result::Result<T, AuthError>;
#[instrument]
@@ -40,7 +40,7 @@ pub(super) async fn get_auth<USER: EasyString>(
let user = user.map(|x| x.into());
let method = oauth2::InstalledFlowReturnMethod::Interactive;
let auth = oauth2::InstalledFlowAuthenticator::builder(app_secret, method)
.flow_delegate(Box::new(CustomFlowDelegate::new(user, &crate::CONF)))
.flow_delegate(Box::new(CustomFlowDelegate::new(user)))
.persist_tokens_to_disk(persistent_path)
.force_account_selection(true)
.build()

View File

@@ -26,7 +26,6 @@ pub mod substitutions {
pub enum Location {
Video(usize),
Playlist,
Other,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -83,7 +82,6 @@ pub(crate) fn create_youtube_title(
let max_len = match target {
Location::Video(_) => Some(YOUTUBE_TITLE_MAX_LENGTH),
Location::Playlist => Some(YOUTUBE_TITLE_MAX_LENGTH),
Location::Other => None,
};
let title = shorten_string_if_needed(title, max_len);
Ok(title)
@@ -94,7 +92,6 @@ fn get_title_template(target: Location) -> String {
match target {
Location::Video(_) => templates.video_title,
Location::Playlist => templates.playlist_title,
Location::Other => format!("\"{}\"", ORIGINAL_TITLE),
}
}
fn get_description_template(target: Location) -> String {
@@ -106,7 +103,6 @@ fn get_description_template(target: Location) -> String {
match target {
Location::Video(_) => templates.video_description,
Location::Playlist => templates.playlist_description,
Location::Other => templates.video_description,
}
}
@@ -220,13 +216,6 @@ mod test {
assert_eq!("123456789", test);
}
#[test]
fn test_create_youtube_title_other() {
let (x, user) = get_test_sample_data();
let description = create_youtube_title(&x, &user, Location::Other).unwrap();
assert_eq!("\"wow\"", description);
}
#[test]
fn test_create_youtube_title_playlist() {
let (x, user) = get_test_sample_data();

View File

@@ -1,5 +1,6 @@
use crate::errors::AuthError;
use crate::prelude::*;
use google_youtube3::oauth2::authenticator_delegate::InstalledFlowDelegate;
use std::{
fmt::{Debug, Formatter},
future::Future,
@@ -7,9 +8,7 @@ use std::{
pin::Pin,
};
use tracing::instrument;
use twba_backup_config::Conf;
use twba_common::notify::NotificationRequest;
use google_youtube3::oauth2::authenticator_delegate::InstalledFlowDelegate;
pub struct CustomFlowDelegate<USER: EasyString> {
user: Option<USER>,
@@ -23,7 +22,7 @@ impl<USER: EasyString> Debug for CustomFlowDelegate<USER> {
}
}
impl<USER: EasyString> CustomFlowDelegate<USER> {
pub(crate) fn new(user: Option<USER>, config: &'static Conf) -> Self {
pub(crate) fn new(user: Option<USER>) -> Self {
Self { user }
}
}

View File

@@ -6,7 +6,7 @@ pub(crate) use std::result::Result as StdResult;
pub type Result<T> = StdResult<T, UploaderError>;
pub(crate) use tracing::{debug, error, info, trace, warn};
pub(crate) use twba_common::prelude::{twba_backup_config, twba_local_db};
pub(crate) use twba_common::prelude::twba_local_db;
pub trait EasyString: Into<String> + Clone + Debug + Send + Sync {}
impl<T> EasyString for T where T: Into<String> + Clone + Debug + Send + Sync {}