backuping...

Signed-off-by: Ivan Bushchik <ivabus@ivabus.dev>
This commit is contained in:
Ivan Bushchik 2023-11-05 19:54:42 +03:00
parent 2037e284b6
commit e499e25fba
No known key found for this signature in database
GPG key ID: 2F16FBF3262E090C
4 changed files with 167 additions and 70 deletions

0
src/create.rs Normal file
View file

37
src/edit.rs Normal file
View file

@ -0,0 +1,37 @@
use rocket::form::validate::Contains;
use std::ffi::OsString;
use std::fs::DirBuilder;
use std::path::PathBuf;
pub fn concat(m3u8: PathBuf) {
todo!(); // OBS can remux files into .mp4 so I don't need to implement this at
// the moment
/*
if !m3u8.exists() {
eprintln!(
"{}: {}: No such file or directory",
std::env::args().next().unwrap(),
m3u8.to_str().unwrap()
);
std::process::exit(1);
}
let _dir = std::fs::read_dir(m3u8.parent().unwrap()).unwrap();
let mut tsFiles: Vec<PathBuf> = vec![];
for i in _dir {
let file = i.unwrap();
if &file.file_name().to_str().unwrap() == &".DS_Store" {
continue;
}
if file.file_name().to_str().unwrap().as_bytes().ends_with(b".ts") {
tsFiles.push(file.path());
}
}
tsFiles.sort();
println!("{:#?}", tsFiles);
*/
}
pub fn split(file: PathBuf) {
todo!()
}

View file

@ -22,92 +22,76 @@
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
*/ */
mod create;
mod edit;
mod serve;
#[macro_use] #[macro_use]
extern crate rocket; extern crate rocket;
use clap::Parser; use clap::{Parser, Subcommand};
use rocket::fs::FileServer; use rocket::fs::FileServer;
use rocket::response::content::RawHtml;
use std::fs::read_dir;
use std::path::PathBuf; use std::path::PathBuf;
const INDEX: &'static str = include_str!("../index.html"); const INDEX: &'static str = include_str!("../index.html");
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)] #[command(author, version, about, long_about = None)]
struct Args { enum Commands {
#[arg(short, long)] /// Run server instance
streams_dir: String, #[command(visible_alias("s"))]
Serve {
streams_dir: PathBuf,
},
/// Edit ended HLS streams
#[command(subcommand, visible_alias("e"))]
Edit(EditCommands),
/// Split file into stream
#[command(visible_alias("c"))]
Create {
freq: f64,
file: PathBuf,
},
} }
#[get("/play/<page..>")] #[derive(Subcommand, Debug)]
fn play(page: PathBuf) -> RawHtml<String> { enum EditCommands {
RawHtml(format!( /// Join hls stream into one file
"<video controls width=\"100%\"> #[command(visible_alias("c"))]
<source src=\"/{}\" type=\"application/x-mpegURL\"> Concat {
</video>", m3u8: PathBuf,
page.to_str().unwrap() },
))
}
struct StreamURL {
alias: String,
url: String,
}
#[get("/")]
fn index() -> RawHtml<String> {
let args = Args::parse();
let dir = read_dir(args.streams_dir).unwrap();
let mut res = INDEX.to_string();
let mut m3u8: Vec<StreamURL> = vec![];
for i in dir {
let path = i.unwrap().path();
if path.is_file() && path.file_name().unwrap().to_str().unwrap() != ".DS_Store" {
if path.extension().unwrap().to_str().unwrap() == "m3u8" {
let filename = path.file_name().unwrap().to_str().unwrap();
m3u8.push(StreamURL {
url: filename.to_string(),
alias: filename.to_string(),
});
}
}
if path.is_dir() {
let mut dir: Vec<String> = vec![];
for i in read_dir(&path).unwrap() {
dir.push(i.unwrap().file_name().to_str().unwrap().to_string())
}
for i in &dir {
if i.contains(".m3u8") {
m3u8.push(StreamURL {
alias: path.file_name().unwrap().to_str().unwrap().to_string(),
url: format!("{}/{}", path.file_name().unwrap().to_str().unwrap(), i),
});
}
}
}
}
m3u8.sort_by_key(|x| x.alias.clone());
if m3u8.len() == 0 {
res += "No streams available";
}
for i in m3u8 {
res += &*format!(
"<a href=\"{}\">{}</a> <a href=\"/play/{}\">Play</a> (copy link into your player)<br>",
&i.url, &i.alias, &i.url
);
}
RawHtml(res)
} }
#[rocket::main] #[rocket::main]
async fn main() -> Result<(), rocket::Error> { async fn main() -> Result<(), rocket::Error> {
let args = Args::parse(); let args = Commands::parse();
let _rocket = rocket::build() println!("{:#?}", args);
.mount("/", routes![play, index]) match args {
.mount("/", FileServer::from(args.streams_dir)) Commands::Serve {
.launch() streams_dir,
.await?; } => {
let _rocket = rocket::build()
.mount("/", routes![serve::play, serve::index])
.mount("/", FileServer::from(streams_dir))
.launch()
.await?;
}
Commands::Edit(command) => match command {
EditCommands::Concat {
m3u8,
} => {
edit::concat(m3u8);
}
},
Commands::Create {
file: _,
freq: _,
} => {
todo!()
}
};
Ok(()) Ok(())
} }

76
src/serve.rs Normal file
View file

@ -0,0 +1,76 @@
use crate::{Commands, INDEX};
use clap::Parser;
use rocket::response::content::RawHtml;
use std::fs::read_dir;
use std::path::PathBuf;
#[get("/play/<page..>")]
pub fn play(page: PathBuf) -> RawHtml<String> {
RawHtml(format!(
"<video controls width=\"100%\">
<source src=\"/{}\" type=\"application/x-mpegURL\">
</video>",
page.to_str().unwrap()
))
}
struct StreamURL {
alias: String,
url: String,
}
#[get("/")]
pub fn index() -> RawHtml<String> {
let args = Commands::parse();
match args {
Commands::Serve {
streams_dir,
} => {
let dir = read_dir(streams_dir).unwrap();
let mut res = INDEX.to_string();
let mut m3u8: Vec<StreamURL> = vec![];
for i in dir {
let path = i.unwrap().path();
if path.is_file() && path.file_name().unwrap().to_str().unwrap() != ".DS_Store" {
if path.extension().unwrap().to_str().unwrap() == "m3u8" {
let filename = path.file_name().unwrap().to_str().unwrap();
m3u8.push(StreamURL {
url: filename.to_string(),
alias: filename.to_string(),
});
}
}
if path.is_dir() {
let mut dir: Vec<String> = vec![];
for i in read_dir(&path).unwrap() {
dir.push(i.unwrap().file_name().to_str().unwrap().to_string())
}
for i in &dir {
if i.contains(".m3u8") {
m3u8.push(StreamURL {
alias: path.file_name().unwrap().to_str().unwrap().to_string(),
url: format!(
"{}/{}",
path.file_name().unwrap().to_str().unwrap(),
i
),
});
}
}
}
}
m3u8.sort_by_key(|x| x.alias.clone());
if m3u8.len() == 0 {
res += "No streams available";
}
for i in m3u8 {
res += &*format!(
"<a href=\"{}\">{}</a> <a href=\"/play/{}\">Play</a> (copy link into your player)<br>",
&i.url, &i.alias, &i.url
);
}
RawHtml(res)
}
_ => unreachable!(),
}
}