* /api/categories/<cat> is now working properly
Output should be correct for the frontend
This commit is contained in:
parent
d0413cfff2
commit
b9c4cb7c6b
81
api/src/category.rs
Normal file
81
api/src/category.rs
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
use base64;
|
||||||
|
use serde::Serialize;
|
||||||
|
use std::fs::DirEntry;
|
||||||
|
use std::{io, env};
|
||||||
|
use rocket::serde::json::Json;
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
pub struct Category {
|
||||||
|
name: String,
|
||||||
|
thumbnail: Option<String>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct List {
|
||||||
|
categories: Vec<Category>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fn get_category_metadata(entry: DirEntry) -> io::Result<(String, Option<String>)> {
|
||||||
|
use std::io::Read;
|
||||||
|
let name = entry.file_name().to_string_lossy().to_string();
|
||||||
|
let mut p = entry.path(); p.push(".thumbnail.jpg");
|
||||||
|
if p.is_file() {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
let mut file = std::fs::File::open(p)?;
|
||||||
|
file.read_to_end(&mut buf)?;
|
||||||
|
|
||||||
|
let nail = base64::encode(buf).to_string();
|
||||||
|
return match nail.len() {
|
||||||
|
0 => Ok((name, None)),
|
||||||
|
_ => Ok((name, Some(nail)))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return Ok((String::new(), None));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_category_dirs(path: &str) -> std::io::Result<Vec<DirEntry>> {
|
||||||
|
let path = std::path::Path::new(path);
|
||||||
|
if !path.is_dir() {
|
||||||
|
panic!("<{:?}> is not a valid directory", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut ret: Vec<DirEntry> = Vec::new();
|
||||||
|
for entry in std::fs::read_dir(path)? {
|
||||||
|
if let Ok(entry) = entry {
|
||||||
|
ret.push(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/categories")]
|
||||||
|
pub fn list() -> Json<Vec<Category>> {
|
||||||
|
// WARN: misconfigured servers are just going to get shafted and serve up
|
||||||
|
// a tonne of 500's
|
||||||
|
let dir = match env::var("CLIPS_DIR") {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(_) => "/media/clips/".to_string()
|
||||||
|
};
|
||||||
|
match get_category_dirs(&dir) {
|
||||||
|
Ok(entries) => {
|
||||||
|
let mut cats: Vec<Category> = Vec::new();
|
||||||
|
for ent in entries {
|
||||||
|
match get_category_metadata(ent) {
|
||||||
|
Ok((name, thumbnail)) => {
|
||||||
|
cats.push(Category {name, thumbnail});
|
||||||
|
},
|
||||||
|
_ => continue
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return Json(cats);
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("ERROR: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Json(Vec::new())
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@ use std::env;
|
|||||||
use rocket_dyn_templates::Template;
|
use rocket_dyn_templates::Template;
|
||||||
|
|
||||||
mod page;
|
mod page;
|
||||||
|
mod category;
|
||||||
mod video;
|
mod video;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
@ -16,7 +17,7 @@ async fn main() {
|
|||||||
*/
|
*/
|
||||||
let _ = rocket::build()
|
let _ = rocket::build()
|
||||||
.mount("/", routes![page::home, page::category, page::video, page::files])
|
.mount("/", routes![page::home, page::category, page::video, page::files])
|
||||||
.mount("/api", routes![video::list_categories])
|
.mount("/api", routes![category::list, video::list])
|
||||||
.attach(Template::fairing())
|
.attach(Template::fairing())
|
||||||
.launch().await;
|
.launch().await;
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ pub async fn home() -> Template {
|
|||||||
#[get("/category/<cat>")]
|
#[get("/category/<cat>")]
|
||||||
pub async fn category(cat: String) -> Template {
|
pub async fn category(cat: String) -> Template {
|
||||||
let mut h: HashMap<&'static str, &'static str> = HashMap::new();
|
let mut h: HashMap<&'static str, &'static str> = HashMap::new();
|
||||||
h.insert("script_src", "/js/category.js");
|
h.insert("script_src", "category.js");
|
||||||
h.insert("page", "category");
|
h.insert("page", "category");
|
||||||
|
|
||||||
return Template::render("list", &h);
|
return Template::render("list", &h);
|
||||||
|
124
api/src/video.rs
124
api/src/video.rs
@ -1,81 +1,89 @@
|
|||||||
use base64;
|
use std::env;
|
||||||
use serde::Serialize;
|
|
||||||
use std::fs::DirEntry;
|
use std::fs::DirEntry;
|
||||||
use std::{io, env};
|
use serde::Serialize;
|
||||||
use rocket::serde::json::Json;
|
use rocket::serde::json::Json;
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct Category {
|
pub struct VideoPreview {
|
||||||
name: String,
|
name: String,
|
||||||
thumbnail: Option<String>
|
thumbnail: Option<String>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
fn vid_file_entries(path: &str) -> std::io::Result<Vec<DirEntry>> {
|
||||||
struct List {
|
|
||||||
categories: Vec<Category>
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn get_category_metadata(entry: DirEntry) -> io::Result<(String, Option<String>)> {
|
|
||||||
use std::io::Read;
|
|
||||||
let name = entry.file_name().to_string_lossy().to_string();
|
|
||||||
let mut p = entry.path(); p.push(".thumbnail.jpg");
|
|
||||||
if p.is_file() {
|
|
||||||
let mut buf = Vec::new();
|
|
||||||
let mut file = std::fs::File::open(p)?;
|
|
||||||
file.read_to_end(&mut buf)?;
|
|
||||||
|
|
||||||
let nail = base64::encode(buf).to_string();
|
|
||||||
return match nail.len() {
|
|
||||||
0 => Ok((name, None)),
|
|
||||||
_ => Ok((name, Some(nail)))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return Ok((String::new(), None));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_category_dirs(path: &str) -> std::io::Result<Vec<DirEntry>> {
|
|
||||||
let path = std::path::Path::new(path);
|
let path = std::path::Path::new(path);
|
||||||
if !path.is_dir() {
|
if !path.is_dir() {
|
||||||
panic!("<{:?}> is not a valid directory", path);
|
panic!("<{:?}> is not a valid directory", path);
|
||||||
}
|
}
|
||||||
|
let mut entries: Vec<DirEntry> = Vec::new();
|
||||||
let mut ret: Vec<DirEntry> = Vec::new();
|
for ent in path.read_dir()? {
|
||||||
for entry in std::fs::read_dir(path)? {
|
if let Ok(ent) = ent {
|
||||||
if let Ok(entry) = entry {
|
let name = ent.file_name().into_string().unwrap();
|
||||||
ret.push(entry)
|
if name.ends_with("mkv") || name.ends_with("mp4") || name.ends_with("webm") {
|
||||||
|
entries.push(ent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Ok(ret);
|
}
|
||||||
|
return Ok(entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/categories")]
|
pub fn get_thumbnail(clips_dir: &str, vid_file: &str) -> std::io::Result<Option<String>> {
|
||||||
pub async fn list_categories() -> Json<Vec<Category>> {
|
use std::io::Read;
|
||||||
// WARN: misconfigured servers are just going to get shafted and serve up
|
// Contruct the full path to the video file itself
|
||||||
// a tonne of 500's
|
// NOTE: thumbnail file names are basically file.mkv.jpg
|
||||||
let dir = match env::var("CLIPS_DIR") {
|
let path = {
|
||||||
|
let mut s = clips_dir.to_string();
|
||||||
|
s.push_str("/thumbnails/");
|
||||||
|
s.push_str(vid_file);
|
||||||
|
s.push_str(".jpg");
|
||||||
|
s
|
||||||
|
};
|
||||||
|
let path = std::path::Path::new(&path);
|
||||||
|
|
||||||
|
if !path.is_file() {
|
||||||
|
println!("File {:?} not found", path);
|
||||||
|
return Ok(None)
|
||||||
|
}
|
||||||
|
println!("Found file {:?}", path);
|
||||||
|
|
||||||
|
// Read into a vec so that base64 can deal with it
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
let mut file = std::fs::File::open(path)?;
|
||||||
|
file.read_to_end(&mut buf)?;
|
||||||
|
|
||||||
|
let nail = base64::encode(buf).to_string();
|
||||||
|
return match nail.len() {
|
||||||
|
0 => Ok(None),
|
||||||
|
_ => Ok(Some(nail))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/category/<cat>")]
|
||||||
|
pub fn list(cat: String) -> Json<Vec<VideoPreview>> {
|
||||||
|
// Strip out any and all '..' from the string
|
||||||
|
// Doing this to avoid any directory traversal memes
|
||||||
|
let cat = cat.replace("..","");
|
||||||
|
|
||||||
|
// Target the directory of clips that we're looking for
|
||||||
|
let mut clips_dir = match env::var("CLIPS_DIR") {
|
||||||
Ok(val) => val,
|
Ok(val) => val,
|
||||||
Err(_) => "/media/clips/".to_string()
|
Err(_) => "/media/clips/".to_string()
|
||||||
};
|
};
|
||||||
match get_category_dirs(&dir) {
|
clips_dir.push('/'); clips_dir.push_str(&cat);
|
||||||
Ok(entries) => {
|
let thumbs_dir = clips_dir.clone();
|
||||||
let mut cats: Vec<Category> = Vec::new();
|
|
||||||
for ent in entries {
|
let mut json: Vec<VideoPreview> = Vec::new();
|
||||||
match get_category_metadata(ent) {
|
// Grab direntires to all the target files
|
||||||
Ok((name, thumbnail)) => {
|
let vid_files = vid_file_entries(&clips_dir).unwrap();
|
||||||
cats.push(Category {name, thumbnail});
|
for vf in vid_files {
|
||||||
},
|
// jfc this is rarted
|
||||||
_ => continue
|
let name = vf.file_name().to_string_lossy().to_string();
|
||||||
|
let thumbnail = match get_thumbnail(&thumbs_dir, &name) {
|
||||||
|
Ok(val) => val,
|
||||||
|
_ => None
|
||||||
|
};
|
||||||
|
json.push(VideoPreview { name, thumbnail })
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
return Json(json)
|
||||||
return Json(cats);
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("ERROR: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Json(Vec::new())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user