Compare commits
No commits in common. "cd10c64a1f96703894de9e40a95fd81cc50d244a" and "2097bd1ccabd1d46849d09398c989d04f95bca2b" have entirely different histories.
cd10c64a1f
...
2097bd1cca
4 changed files with 41 additions and 105 deletions
|
@ -31,4 +31,3 @@ reqwest = { version = "0.11", features = ["blocking"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
cache = []
|
cache = []
|
||||||
htmx = []
|
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
use based::get_pg;
|
|
||||||
use based::request::RequestContext;
|
|
||||||
|
|
||||||
use rocket::get;
|
|
||||||
use rocket::response::Responder;
|
|
||||||
use rocket::routes;
|
|
||||||
|
|
||||||
#[get("/")]
|
|
||||||
pub async fn index_page<'r>(ctx: RequestContext) -> impl Responder<'r, 'static> {
|
|
||||||
based::request::assets::DataResponse::new(
|
|
||||||
include_bytes!("../Cargo.toml").to_vec(),
|
|
||||||
"text/toml",
|
|
||||||
Some(60 * 60 * 3),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rocket::launch]
|
|
||||||
async fn launch() -> _ {
|
|
||||||
// Logging
|
|
||||||
env_logger::init();
|
|
||||||
|
|
||||||
// Database
|
|
||||||
let pg = get_pg!();
|
|
||||||
// sqlx::migrate!("./migrations").run(pg).await.unwrap();
|
|
||||||
|
|
||||||
rocket::build().mount("/", routes![index_page])
|
|
||||||
}
|
|
|
@ -2,12 +2,14 @@ use tokio::sync::OnceCell;
|
||||||
|
|
||||||
pub mod auth;
|
pub mod auth;
|
||||||
pub mod format;
|
pub mod format;
|
||||||
#[cfg(feature = "htmx")]
|
|
||||||
pub mod htmx;
|
|
||||||
pub mod page;
|
pub mod page;
|
||||||
pub mod request;
|
pub mod request;
|
||||||
pub mod result;
|
pub mod result;
|
||||||
|
pub mod htmx;
|
||||||
|
|
||||||
|
// TODO : Cache Headers
|
||||||
|
// TODO : Refactor Responders
|
||||||
|
// TODO : Streaming Responses + Ranges
|
||||||
// TODO : API Pagination?
|
// TODO : API Pagination?
|
||||||
// TODO : CORS?
|
// TODO : CORS?
|
||||||
// TODO : CSRF?
|
// TODO : CSRF?
|
||||||
|
|
|
@ -1,87 +1,49 @@
|
||||||
use rocket::Request;
|
// TODO : Implement
|
||||||
use rocket::Response;
|
|
||||||
use rocket::http::Header;
|
|
||||||
use rocket::http::Status;
|
|
||||||
use rocket::response::Responder;
|
|
||||||
use std::io::Cursor;
|
|
||||||
|
|
||||||
// TODO: Implement file based response
|
/*
|
||||||
|
|
||||||
pub struct DataResponse {
|
#[get("/video/raw?<v>")]
|
||||||
data: Vec<u8>,
|
pub async fn video_file(
|
||||||
content_type: String,
|
v: &str,
|
||||||
cache_duration: Option<u64>,
|
library: &State<Library>,
|
||||||
}
|
) -> Option<(Status, (ContentType, Vec<u8>))> {
|
||||||
|
let video = if let Some(video) = library.get_video_by_id(v).await {
|
||||||
impl DataResponse {
|
video
|
||||||
pub fn new(data: Vec<u8>, content_type: &str, cache_duration: Option<u64>) -> Self {
|
|
||||||
Self {
|
|
||||||
data,
|
|
||||||
content_type: content_type.to_string(),
|
|
||||||
cache_duration,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rocket::async_trait]
|
|
||||||
impl<'r> Responder<'r, 'static> for DataResponse {
|
|
||||||
fn respond_to(self, req: &'r Request<'_>) -> rocket::response::Result<'static> {
|
|
||||||
// Handle Range requests
|
|
||||||
if let Some(range) = req.headers().get_one("Range") {
|
|
||||||
if let Some((start, end)) = parse_range_header(range, self.data.len()) {
|
|
||||||
// TODO : Reject invalid ranges
|
|
||||||
// TODO : Multiple ranges?
|
|
||||||
|
|
||||||
let sliced_data = &self.data[start..=end];
|
|
||||||
return Ok(Response::build()
|
|
||||||
.header(Header::new(
|
|
||||||
"Content-Range",
|
|
||||||
format!("bytes {}-{}/{}", start, end, self.data.len()),
|
|
||||||
))
|
|
||||||
.header(Header::new("Accept-Ranges", "bytes"))
|
|
||||||
.header(Header::new("Content-Type", self.content_type.clone()))
|
|
||||||
.status(Status::PartialContent)
|
|
||||||
.streamed_body(Cursor::new(sliced_data.to_vec()))
|
|
||||||
.finalize());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add caching headers for static files
|
|
||||||
let cache_control_header = if let Some(duration) = self.cache_duration {
|
|
||||||
Header::new("Cache-Control", format!("public, max-age={}", duration))
|
|
||||||
} else {
|
} else {
|
||||||
Header::new("Cache-Control", "no-cache")
|
library.get_video_by_youtube_id(v).await.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Response::build()
|
if let Ok(mut file) = File::open(&video.path).await {
|
||||||
.header(cache_control_header)
|
let mut buf = Vec::with_capacity(51200);
|
||||||
.header(Header::new("Accept-Ranges", "bytes"))
|
file.read_to_end(&mut buf).await.ok()?;
|
||||||
.header(Header::new("Content-Type", self.content_type))
|
let content_type = if video.path.ends_with("mp4") {
|
||||||
.streamed_body(Cursor::new(self.data))
|
ContentType::new("video", "mp4")
|
||||||
.finalize())
|
} else {
|
||||||
|
ContentType::new("video", "webm")
|
||||||
|
};
|
||||||
|
|
||||||
|
return Some((Status::Ok, (content_type, buf)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse the Range header and return the start and end indices.
|
#[get("/video/thumbnail?<v>")]
|
||||||
fn parse_range_header(range: &str, total_len: usize) -> Option<(usize, usize)> {
|
pub async fn video_thumbnail(
|
||||||
if !range.starts_with("bytes=") {
|
v: &str,
|
||||||
return None;
|
library: &State<Library>,
|
||||||
|
) -> Option<(Status, (ContentType, Vec<u8>))> {
|
||||||
|
let video = if let Some(video) = library.get_video_by_id(v).await {
|
||||||
|
video
|
||||||
|
} else {
|
||||||
|
library.get_video_by_youtube_id(v).await.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(data) = library.get_thumbnail(&video).await {
|
||||||
|
return Some((Status::Ok, (ContentType::PNG, data)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let range = &range[6..];
|
None
|
||||||
let parts: Vec<&str> = range.split('-').collect();
|
|
||||||
|
|
||||||
if parts.len() != 2 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let start = parts[0].parse::<usize>().ok();
|
|
||||||
let end = parts[1].parse::<usize>().ok();
|
|
||||||
|
|
||||||
match (start, end) {
|
|
||||||
(Some(start), Some(end)) if start <= end && end < total_len => Some((start, end)),
|
|
||||||
(Some(start), None) if start < total_len => Some((start, total_len - 1)),
|
|
||||||
(None, Some(end)) if end < total_len => Some((0, end)),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue