mirror of
https://framagit.org/veretcle/tootube.git
synced 2025-07-20 20:41:17 +02:00
Initial commit
This commit is contained in:
31
src/config.rs
Normal file
31
src/config.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
use std::fs::read_to_string;
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
// General configuration Struct
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Config {
|
||||
pub peertube: PeertubeConfig,
|
||||
pub youtube: YoutubeConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct PeertubeConfig {
|
||||
pub base_url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct YoutubeConfig {
|
||||
pub api_key: String,
|
||||
}
|
||||
|
||||
/// Parses the TOML file into a Config struct
|
||||
pub fn parse_toml(toml_file: &str) -> Config {
|
||||
let toml_config =
|
||||
read_to_string(toml_file).unwrap_or_else(|e| panic!("Cannot open file {toml_file}: {e}"));
|
||||
|
||||
let config: Config = toml::from_str(&toml_config)
|
||||
.unwrap_or_else(|e| panic!("Cannot parse TOML file {toml_file}: {e}"));
|
||||
|
||||
config
|
||||
}
|
17
src/lib.rs
Normal file
17
src/lib.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
mod config;
|
||||
pub use config::parse_toml;
|
||||
use config::Config;
|
||||
|
||||
mod peertube;
|
||||
use peertube::{get_latest_video, get_max_resolution_dl};
|
||||
|
||||
pub fn run(config: Config) {
|
||||
// Get the latest video object
|
||||
let latest_vid = get_latest_video(&config.peertube.base_url).unwrap_or_else(|e| {
|
||||
panic!("Cannot retrieve the latest video, something must have gone terribly wrong: {e}")
|
||||
});
|
||||
|
||||
let dl_url = get_max_resolution_dl(&latest_vid.streaming_playlists.unwrap());
|
||||
|
||||
println!("{dl_url}");
|
||||
}
|
25
src/main.rs
Normal file
25
src/main.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
use clap::{Arg, Command};
|
||||
use tootube::*;
|
||||
|
||||
const DEFAULT_CONFIG_PATH: &str = "/usr/local/etc/tootube.toml";
|
||||
|
||||
fn main() {
|
||||
let matches = Command::new(env!("CARGO_PKG_NAME"))
|
||||
.version(env!("CARGO_PKG_VERSION"))
|
||||
.about("A simple PeerTube to YouTube converter")
|
||||
.arg(
|
||||
Arg::new("config")
|
||||
.short('c')
|
||||
.long("config")
|
||||
.value_name("CONFIG_FILE")
|
||||
.help("TOML config file for tootube")
|
||||
.num_args(1)
|
||||
.default_value(DEFAULT_CONFIG_PATH)
|
||||
.display_order(1),
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
let config = parse_toml(matches.get_one::<String>("config").unwrap());
|
||||
|
||||
run(config);
|
||||
}
|
90
src/peertube.rs
Normal file
90
src/peertube.rs
Normal file
@@ -0,0 +1,90 @@
|
||||
use serde::Deserialize;
|
||||
use std::{boxed::Box, error::Error};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct PeerTubeVideos {
|
||||
pub total: u64,
|
||||
pub data: Vec<PeerTubeVideo>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct PeerTubeVideo {
|
||||
pub name: String,
|
||||
pub uuid: String,
|
||||
pub description: String,
|
||||
#[serde(rename = "streamingPlaylists")]
|
||||
pub streaming_playlists: Option<Vec<PeerTubeVideoStreamingPlaylists>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct PeerTubeVideoStreamingPlaylists {
|
||||
pub files: Vec<PeerTubeVideoStreamingPlaylistsFiles>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct PeerTubeVideoStreamingPlaylistsFiles {
|
||||
pub id: u64,
|
||||
pub resolution: PeerTubeVideoStreamingPlaylistsFilesResolution,
|
||||
#[serde(rename = "fileDownloadUrl")]
|
||||
pub file_download_url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct PeerTubeVideoStreamingPlaylistsFilesResolution {
|
||||
pub id: u16,
|
||||
}
|
||||
|
||||
/// This gets the last video uploaded to the PeerTube server
|
||||
pub fn get_latest_video(u: &str) -> Result<PeerTubeVideo, Box<dyn Error>> {
|
||||
let body = reqwest::blocking::get(format!("{}/api/v1/videos?count=1&sort=-publishedAt", u))?
|
||||
.json::<PeerTubeVideos>()?;
|
||||
|
||||
let vid = get_video_detail(u, &body.data[0].uuid)?;
|
||||
|
||||
Ok(vid)
|
||||
}
|
||||
|
||||
/// This returns the direct download URL for with the maximum resolution
|
||||
pub fn get_max_resolution_dl(p: &Vec<PeerTubeVideoStreamingPlaylists>) -> String {
|
||||
let max_res = p[0].files.iter().fold(std::u16::MIN, |a,b| a.resolution.id.max(&b.resolution.id));
|
||||
// let mut res = 0;
|
||||
// let mut dl_url = String::new();
|
||||
//
|
||||
// for i in p[0].files.iter() {
|
||||
// if i.resolution.id > res {
|
||||
// res = i.resolution.id;
|
||||
// dl_url = i.file_download_url.clone();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// dl_url
|
||||
"blah".to_string()
|
||||
}
|
||||
|
||||
/// This gets all the crispy details about one particular video
|
||||
fn get_video_detail(u: &str, v: &str) -> Result<PeerTubeVideo, Box<dyn Error>> {
|
||||
let body =
|
||||
reqwest::blocking::get(format!("{}/api/v1/videos/{}", u, v))?.json::<PeerTubeVideo>()?;
|
||||
|
||||
Ok(body)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_get_max_resolution_dl() {
|
||||
let str_plist: Vec<PeerTubeVideoStreamingPlaylists> = vec![
|
||||
PeerTubeVideoStreamingPlaylists {
|
||||
files: vec![PeerTubeVideoStreamingPlaylistsFiles { id: 1025, resolution: PeerTubeVideoStreamingPlaylistsFilesResolution { id: 990 }, file_download_url: "meh!".to_string() },
|
||||
PeerTubeVideoStreamingPlaylistsFiles { id: 1027, resolution: PeerTubeVideoStreamingPlaylistsFilesResolution { id: 1720 }, file_download_url: "blah".to_string() },
|
||||
PeerTubeVideoStreamingPlaylistsFiles { id: 1026, resolution: PeerTubeVideoStreamingPlaylistsFilesResolution { id: 360 }, file_download_url: "nope".to_string() },
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
assert_eq!("blah".to_string(), get_max_resolution_dl(&str_plist));
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user