aboutsummaryrefslogtreecommitdiff
path: root/server/src/routes
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/routes')
-rw-r--r--server/src/routes/mod.rs6
-rw-r--r--server/src/routes/stream.rs43
-rw-r--r--server/src/routes/ui/player.rs16
3 files changed, 48 insertions, 17 deletions
diff --git a/server/src/routes/mod.rs b/server/src/routes/mod.rs
index 6fe5018..94a7547 100644
--- a/server/src/routes/mod.rs
+++ b/server/src/routes/mod.rs
@@ -45,10 +45,7 @@ macro_rules! uri {
};
}
-pub fn build_rocket(
- database: Database,
- federation: Federation,
-) -> Rocket<Build> {
+pub fn build_rocket(database: Database, federation: Federation) -> Rocket<Build> {
rocket::build()
.configure(Config {
address: std::env::var("BIND_ADDR")
@@ -66,6 +63,7 @@ pub fn build_rocket(
})
.as_bytes(),
),
+ ip_header: Some("x-forwarded-for".into()),
..Default::default()
})
.manage(database)
diff --git a/server/src/routes/stream.rs b/server/src/routes/stream.rs
index c47f589..018fae5 100644
--- a/server/src/routes/stream.rs
+++ b/server/src/routes/stream.rs
@@ -10,14 +10,29 @@ use jellybase::CONF;
use jellycommon::{stream::StreamSpec, MediaSource};
use log::{info, warn};
use rocket::{
- get,
- http::{ContentType, Header, Status},
+ get, head,
+ http::{Header, Status},
request::{self, FromRequest},
response::{self, Redirect, Responder},
Either, Request, Response, State,
};
use std::{ops::Range, time::Duration};
-use tokio::io::DuplexStream;
+use tokio::io::{duplex, DuplexStream};
+
+#[head("/n/<_id>/stream?<spec>")]
+pub async fn r_stream_head(
+ _sess: Session,
+ _id: &str,
+ spec: StreamSpec,
+) -> Result<Either<StreamResponse, Redirect>, MyError> {
+ let head = jellystream::stream_head(&spec);
+ Ok(Either::Left(StreamResponse {
+ stream: duplex(0).0,
+ advertise_range: head.range_supported,
+ content_type: head.content_type,
+ range: None,
+ }))
+}
#[get("/n/<id>/stream?<spec>")]
pub async fn r_stream(
@@ -28,7 +43,10 @@ pub async fn r_stream(
range: Option<RequestRange>,
spec: StreamSpec,
) -> Result<Either<StreamResponse, Redirect>, MyError> {
- let node = db.node.get(&id.to_string())?.ok_or(anyhow!("node does not exist"))?;
+ let node = db
+ .node
+ .get(&id.to_string())?
+ .ok_or(anyhow!("node does not exist"))?;
let source = node
.private
.source
@@ -70,8 +88,15 @@ pub async fn r_stream(
None => 0..(isize::MAX as usize),
};
+ let head = jellystream::stream_head(&spec);
+
match jellystream::stream(node, spec, urange).await {
- Ok(stream) => Ok(Either::Left(StreamResponse { stream, range })),
+ Ok(stream) => Ok(Either::Left(StreamResponse {
+ stream,
+ range,
+ advertise_range: head.range_supported,
+ content_type: head.content_type,
+ })),
Err(e) => {
warn!("stream error: {e}");
Err(MyError(e))
@@ -81,6 +106,8 @@ pub async fn r_stream(
pub struct StreamResponse {
stream: DuplexStream,
+ advertise_range: bool,
+ content_type: &'static str,
range: Option<RequestRange>,
}
@@ -92,8 +119,10 @@ impl<'r> Responder<'r, 'static> for StreamResponse {
b.status(Status::PartialContent);
b.header(Header::new("content-range", range.to_cr_hv()));
}
- b.header(Header::new("accept-ranges", "bytes"))
- .header(ContentType::WEBM)
+ if self.advertise_range {
+ b.header(Header::new("accept-ranges", "bytes"));
+ }
+ b.header(Header::new("content-type", self.content_type))
.streamed_body(self.stream)
.ok()
}
diff --git a/server/src/routes/ui/player.rs b/server/src/routes/ui/player.rs
index fa9657f..4a636e6 100644
--- a/server/src/routes/ui/player.rs
+++ b/server/src/routes/ui/player.rs
@@ -33,13 +33,16 @@ pub struct PlayerConfig {
}
#[get("/n/<id>/player?<conf..>", rank = 4)]
-pub fn r_player(
+pub fn r_player<'a>(
_sess: Session,
- db: &State<Database>,
- id: String,
+ db: &'a State<Database>,
+ id: &'a str,
conf: PlayerConfig,
-) -> MyResult<DynLayoutPage<'_>> {
- let item = db.node.get(&id)?.ok_or(anyhow!("node does not exist"))?;
+) -> MyResult<DynLayoutPage<'a>> {
+ let item = db
+ .node
+ .get(&id.to_string())?
+ .ok_or(anyhow!("node does not exist"))?;
let spec = StreamSpec {
tracks: None
@@ -48,7 +51,8 @@ pub fn r_player(
.chain(conf.a.into_iter())
.chain(conf.s.into_iter())
.collect::<Vec<_>>(),
- format: StreamFormat::Webm,
+ format: StreamFormat::Matroska,
+ webm: Some(true),
..Default::default()
};