: add peertube source video file

This commit is contained in:
VC
2024-05-13 22:18:58 +02:00
parent bf622d6989
commit 982dc8b954
8 changed files with 435 additions and 136 deletions

View File

@@ -1,5 +1,10 @@
use serde::Deserialize;
use std::{boxed::Box, cmp::Ordering, error::Error};
use crate::{config::PeertubeConfig, error::TootubeError};
use log::debug;
use reqwest::Client;
use rpassword::prompt_password;
use serde::{Deserialize, Serialize};
use std::{boxed::Box, cmp::Ordering, error::Error, io::stdin};
use tokio::fs::{read_to_string, write};
#[derive(Debug, Deserialize)]
pub struct PeerTubeVideos {
@@ -22,6 +27,44 @@ pub struct PeerTubeVideoStreamingPlaylists {
pub files: Vec<PeerTubeVideoStreamingPlaylistsFiles>,
}
#[derive(Debug, Deserialize)]
struct PeerTubeOauthClientsLocalResponse {
client_id: String,
client_secret: String,
}
#[derive(Debug, Serialize)]
struct PeerTubeUsersToken {
client_id: String,
client_secret: String,
grant_type: String,
password: Option<String>,
username: Option<String>,
refresh_token: Option<String>,
}
#[derive(Debug, Deserialize)]
struct PeerTubeUsersTokenResponse {
refresh_token: String,
access_token: String,
}
#[derive(Debug, Deserialize)]
struct PeerTubeVideoSourceResponse {
#[serde(rename = "fileDownloadUrl")]
pub file_download_url: String,
}
#[derive(Debug, Deserialize)]
struct PeerTubeVideoTokenResponse {
files: PeerTubeVideoTokenResponseFiles,
}
#[derive(Debug, Deserialize)]
struct PeerTubeVideoTokenResponseFiles {
token: String,
}
#[derive(Eq, Debug, Deserialize)]
pub struct PeerTubeVideoStreamingPlaylistsFiles {
pub id: u64,
@@ -74,3 +117,163 @@ async fn get_video_detail(u: &str, v: &str) -> Result<PeerTubeVideo, Box<dyn Err
Ok(body)
}
/// This function makes the registration process a little bit easier
#[tokio::main]
pub async fn register(config: &PeertubeConfig) -> Result<(), Box<dyn Error>> {
// Get client ID/secret
let oauth2_client = reqwest::get(format!("{}/api/v1/oauth-clients/local", config.base_url))
.await?
.json::<PeerTubeOauthClientsLocalResponse>()
.await?;
println!(
"Please type your PeerTube username for instance {}:",
config.base_url
);
let mut username = String::new();
stdin()
.read_line(&mut username)
.expect("Unable to read back the username!");
let password = prompt_password("Your password: ").expect("Unable to read back the password!");
let params = PeerTubeUsersToken {
client_id: oauth2_client.client_id.clone(),
client_secret: oauth2_client.client_secret.clone(),
grant_type: "password".to_string(),
username: Some(username.trim().to_string()),
password: Some(password.clone()),
refresh_token: None,
};
let client = Client::new();
let oauth2_token = client
.post(format!("{}/api/v1/users/token", config.base_url))
.form(&params)
.send()
.await?
.json::<PeerTubeUsersTokenResponse>()
.await?;
println!("You can now paste the following lines inside the `peertube` section of your tootube.toml file:");
println!();
println!("[peertube.oauth2]");
println!("client_id=\"{}\"", oauth2_client.client_id);
println!("client_secret=\"{}\"", oauth2_client.client_secret);
println!("refresh_token=<path to refresh_token>");
println!();
println!("Finally, add the refresh token inside the refresh_token path:");
println!("{}", oauth2_token.refresh_token);
Ok(())
}
async fn get_refresh_token(config: &PeertubeConfig) -> Result<String, Box<dyn Error>> {
// unwrap is safe here, this function is only called when oauth2 is present
let oauth2_config = config.oauth2.as_ref().unwrap().clone();
// retrieve the refresh_token from the file
let refresh_token = read_to_string(&oauth2_config.refresh_token).await?;
debug!(
"Opened file {} to retrieve Token",
&oauth2_config.refresh_token
);
let params = PeerTubeUsersToken {
client_id: oauth2_config.client_id.clone(),
client_secret: oauth2_config.client_secret.clone(),
grant_type: "refresh_token".to_string(),
refresh_token: Some(refresh_token),
username: None,
password: None,
};
let client = Client::new();
let oauth2_token = client
.post(format!("{}/api/v1/users/token", config.base_url))
.form(&params)
.send()
.await?
.json::<PeerTubeUsersTokenResponse>()
.await?;
debug!("Retrieved access_token: {}", &oauth2_token.access_token);
// write the new refresh token to the file
write(&oauth2_config.refresh_token, oauth2_token.refresh_token).await?;
debug!(
"Written refresh_token to file {}",
&oauth2_config.refresh_token
);
Ok(oauth2_token.access_token)
}
pub async fn get_original_video_source(
uuid: &str,
config: &PeertubeConfig,
) -> Result<String, Box<dyn Error>> {
let access_token = get_refresh_token(config).await?;
let client = Client::new();
let source_vid = client
.get(format!("{}/api/v1/videos/{}/source", config.base_url, uuid))
.header("Authorization", format!("Bearer {}", &access_token))
.send()
.await?
.json::<PeerTubeVideoSourceResponse>()
.await?;
debug!("Got the Source Vid URL: {}", &source_vid.file_download_url);
let video_file_token = client
.post(format!("{}/api/v1/videos/{}/token", config.base_url, uuid))
.header("Authorization", format!("Bearer {}", &access_token))
.send()
.await?
.json::<PeerTubeVideoTokenResponse>()
.await?;
debug!("Got the File Token: {}", &video_file_token.files.token);
Ok(format!(
"{}?videoFileToken={}",
source_vid.file_download_url, video_file_token.files.token
))
}
pub async fn delete_original_video_source(
uuid: &str,
config: &PeertubeConfig,
) -> Result<(), Box<dyn Error>> {
let access_token = get_refresh_token(config).await?;
let client = Client::new();
let res = client
.delete(format!(
"{}/api/v1/videos/{}/source/file",
config.base_url, uuid
))
.header("Authorization", format!("Bearer {}", &access_token))
.send()
.await?;
if !res.status().is_success() {
return Err(TootubeError::new(&format!(
"Cannot delete source video file {}: {}",
uuid,
res.text().await?
))
.into());
}
Ok(())
}