Compare commits
6 Commits
240f7d7f8d
...
main
Author | SHA1 | Date | |
---|---|---|---|
2411320522 | |||
34811c15af | |||
eebea71fca | |||
9260d80458 | |||
b21863298b | |||
3d252a2604 |
85
Cargo.lock
generated
85
Cargo.lock
generated
@@ -194,6 +194,15 @@ version = "0.8.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "croner"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c344b0690c1ad1c7176fe18eb173e0c927008fdaaa256e40dfd43ddd149c0843"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "displaydoc"
|
name = "displaydoc"
|
||||||
version = "0.2.5"
|
version = "0.2.5"
|
||||||
@@ -689,30 +698,6 @@ version = "0.8.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
|
checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "maud"
|
|
||||||
version = "0.27.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8156733e27020ea5c684db5beac5d1d611e1272ab17901a49466294b84fc217e"
|
|
||||||
dependencies = [
|
|
||||||
"axum-core",
|
|
||||||
"http",
|
|
||||||
"itoa",
|
|
||||||
"maud_macros",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "maud_macros"
|
|
||||||
version = "0.27.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7261b00f3952f617899bc012e3dbd56e4f0110a038175929fa5d18e5a19913ca"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"proc-macro2-diagnostics",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mediatype"
|
name = "mediatype"
|
||||||
version = "0.20.0"
|
version = "0.20.0"
|
||||||
@@ -751,6 +736,17 @@ dependencies = [
|
|||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-derive"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.19"
|
version = "0.2.19"
|
||||||
@@ -824,13 +820,12 @@ dependencies = [
|
|||||||
"axum",
|
"axum",
|
||||||
"bytes",
|
"bytes",
|
||||||
"chrono",
|
"chrono",
|
||||||
"maud",
|
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"stream-download",
|
"stream-download",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tokio-cron-scheduler",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
"tracing",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -860,18 +855,6 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro2-diagnostics"
|
|
||||||
version = "0.10.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quinn"
|
name = "quinn"
|
||||||
version = "0.11.8"
|
version = "0.11.8"
|
||||||
@@ -1361,6 +1344,21 @@ dependencies = [
|
|||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-cron-scheduler"
|
||||||
|
version = "0.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c71ce8f810abc9fabebccc30302a952f9e89c6cf246fafaf170fef164063141"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
"croner",
|
||||||
|
"num-derive",
|
||||||
|
"num-traits",
|
||||||
|
"tokio",
|
||||||
|
"tracing",
|
||||||
|
"uuid",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-macros"
|
name = "tokio-macros"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
@@ -1520,10 +1518,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "uuid"
|
||||||
version = "0.9.5"
|
version = "1.18.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
checksum = "f33196643e165781c20a5ead5582283a7dacbb87855d867fbc2df3f81eddc1be"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.3.3",
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "want"
|
name = "want"
|
||||||
|
@@ -11,7 +11,6 @@ reqwest = { version = "0.12", features = ["stream", "json", "rustls-tls"], defau
|
|||||||
bytes = "1"
|
bytes = "1"
|
||||||
async-stream = "0.3"
|
async-stream = "0.3"
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
tracing = "0.1"
|
|
||||||
stream-download = "0.22"
|
stream-download = "0.22"
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
maud = { version = "0.27", features = ["axum"] }
|
tokio-cron-scheduler = "0.14"
|
||||||
|
@@ -16,10 +16,10 @@ async fn get_newest_morning_journal() -> Result<String, Box<dyn std::error::Erro
|
|||||||
for day in days.iter().rev() {
|
for day in days.iter().rev() {
|
||||||
if let Some(broadcasts) = day["broadcasts"].as_array() {
|
if let Some(broadcasts) = day["broadcasts"].as_array() {
|
||||||
for broadcast in broadcasts.iter().rev() {
|
for broadcast in broadcasts.iter().rev() {
|
||||||
if broadcast["title"] == "Ö1 Morgenjournal" {
|
if broadcast["title"] == "Ö1 Morgenjournal"
|
||||||
if let Some(href) = broadcast["href"].as_str() {
|
&& let Some(href) = broadcast["href"].as_str()
|
||||||
return Ok(href.into());
|
{
|
||||||
}
|
return Ok(href.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
119
src/main.rs
119
src/main.rs
@@ -1,109 +1,38 @@
|
|||||||
mod state;
|
mod state;
|
||||||
mod streamer;
|
mod streamer;
|
||||||
|
|
||||||
use axum::{response::IntoResponse, routing::get, Router};
|
use axum::{routing::get, Router};
|
||||||
use maud::{html, Markup, DOCTYPE};
|
use chrono::Utc;
|
||||||
use reqwest::header;
|
|
||||||
use state::AppState;
|
use state::AppState;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use tokio_cron_scheduler::{Job, JobScheduler};
|
||||||
async fn index() -> Markup {
|
|
||||||
html! {
|
|
||||||
(DOCTYPE)
|
|
||||||
html lang="en" {
|
|
||||||
head {
|
|
||||||
meta charset="utf-8";
|
|
||||||
meta name="viewport" content="user-scalable=no";
|
|
||||||
title { "Ö1 Morgenjournal" }
|
|
||||||
link rel="stylesheet" href="/styles.css";
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
// Top Info
|
|
||||||
div #title {
|
|
||||||
span #track {}
|
|
||||||
div #timer { "0:00" }
|
|
||||||
div #duration { "0:00" }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Controls
|
|
||||||
div .controlsOuter {
|
|
||||||
div .controlsInner {
|
|
||||||
div #loading {}
|
|
||||||
div .btn #playBtn {}
|
|
||||||
div .btn #pauseBtn {}
|
|
||||||
div .btn #prevBtn {}
|
|
||||||
div .btn #nextBtn {}
|
|
||||||
}
|
|
||||||
div .btn #playlistBtn {}
|
|
||||||
div .btn #volumeBtn {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Progress
|
|
||||||
div #waveform {}
|
|
||||||
div #bar {}
|
|
||||||
div #progress {}
|
|
||||||
|
|
||||||
// Playlist
|
|
||||||
div #playlist {
|
|
||||||
div #list {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Volume
|
|
||||||
div #volume .fadeout {
|
|
||||||
div #barFull .bar {}
|
|
||||||
div #barEmpty .bar {}
|
|
||||||
div #sliderBtn {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scripts
|
|
||||||
script src="/howler.core.min.js" {}
|
|
||||||
script src="/siriwave.js" {}
|
|
||||||
script src="/player.js" {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn styles() -> impl IntoResponse {
|
|
||||||
(
|
|
||||||
[(header::CONTENT_TYPE, "text/css")],
|
|
||||||
include_str!("../static/styles.css"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn howler() -> impl IntoResponse {
|
|
||||||
(
|
|
||||||
[(header::CONTENT_TYPE, "text/javascript")],
|
|
||||||
include_str!("../static/howler.core.min.js").to_string(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn player() -> impl IntoResponse {
|
|
||||||
(
|
|
||||||
[(header::CONTENT_TYPE, "text/javascript")],
|
|
||||||
include_str!("../static/player.js").to_string(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn siriwave() -> impl IntoResponse {
|
|
||||||
(
|
|
||||||
[(header::CONTENT_TYPE, "text/javascript")],
|
|
||||||
include_str!("../static/siriwave.js").to_string(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let state = Arc::new(AppState::new());
|
let state = Arc::new(AppState::new());
|
||||||
|
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route("/", get(index))
|
.route("/", get(streamer::stream_handler))
|
||||||
.route("/stream", get(streamer::stream_handler))
|
.with_state(state.clone());
|
||||||
.route("/howler.core.min.js", get(howler))
|
|
||||||
.route("/styles.css", get(styles))
|
//let scheduler = JobScheduler::new().await.unwrap();
|
||||||
.route("/player.js", get(player))
|
//scheduler
|
||||||
.route("/siriwave.js", get(siriwave))
|
// .add(
|
||||||
.with_state(state);
|
// Job::new_async(
|
||||||
|
// "30 0 7 * * Mon,Tue,Wed,Thu,Fri,Sat",
|
||||||
|
// move |_uuid, _locked| {
|
||||||
|
// let state_for_task = state.clone();
|
||||||
|
// Box::pin(async move {
|
||||||
|
// state_for_task.check_update().await;
|
||||||
|
// println!("Task executed at: {}", Utc::now());
|
||||||
|
// })
|
||||||
|
// },
|
||||||
|
// )
|
||||||
|
// .unwrap(),
|
||||||
|
// )
|
||||||
|
// .await
|
||||||
|
// .unwrap();
|
||||||
|
//scheduler.start().await.unwrap();
|
||||||
|
|
||||||
println!("Streaming server running on http://localhost:3029");
|
println!("Streaming server running on http://localhost:3029");
|
||||||
|
|
||||||
|
@@ -25,11 +25,10 @@ impl AppState {
|
|||||||
|
|
||||||
pub async fn check_update(self: Arc<Self>) {
|
pub async fn check_update(self: Arc<Self>) {
|
||||||
let today = Local::now().date_naive();
|
let today = Local::now().date_naive();
|
||||||
if let Some(downloaded_on_day) = *self.downloaded_on_day.read().await {
|
if let Some(downloaded_on_day) = *self.downloaded_on_day.read().await
|
||||||
if today == downloaded_on_day {
|
&& today == downloaded_on_day {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
self.reset().await;
|
self.reset().await;
|
||||||
*self.downloaded_on_day.write().await = Some(today);
|
*self.downloaded_on_day.write().await = Some(today);
|
||||||
|
@@ -1,24 +1,32 @@
|
|||||||
use crate::state::AppState;
|
use crate::state::AppState;
|
||||||
use axum::{body::Body, extract::State, response::Response};
|
use axum::{
|
||||||
|
body::Body,
|
||||||
|
extract::State,
|
||||||
|
response::{Redirect, Response},
|
||||||
|
};
|
||||||
|
use player::newest_morning_journal_streaming_url;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio_stream::Stream;
|
use tokio_stream::Stream;
|
||||||
|
|
||||||
pub async fn stream_handler(State(state): State<Arc<AppState>>) -> Response {
|
pub async fn stream_handler(State(state): State<Arc<AppState>>) -> Redirect {
|
||||||
state.clone().check_update().await;
|
let url = newest_morning_journal_streaming_url().await.unwrap();
|
||||||
|
Redirect::temporary(&url)
|
||||||
|
|
||||||
let stream = create_chunk_stream(state);
|
//state.clone().check_update().await;
|
||||||
let body = Body::from_stream(stream);
|
|
||||||
|
|
||||||
Response::builder()
|
//let stream = create_chunk_stream(state);
|
||||||
.header("Content-Type", "audio/mpeg")
|
//let body = Body::from_stream(stream);
|
||||||
.header("Cache-Control", "no-cache, no-store, must-revalidate")
|
|
||||||
.header("Pragma", "no-cache")
|
//Response::builder()
|
||||||
.header("Expires", "0")
|
// .header("Content-Type", "audio/mpeg")
|
||||||
.header("Accept-Ranges", "none")
|
// .header("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||||
.header("Transfer-Encoding", "chunked")
|
// .header("Pragma", "no-cache")
|
||||||
.header("X-Content-Duration", "infinity")
|
// .header("Expires", "0")
|
||||||
.body(body)
|
// .header("Accept-Ranges", "none")
|
||||||
.unwrap()
|
// .header("Transfer-Encoding", "chunked")
|
||||||
|
// .header("X-Content-Duration", "infinity")
|
||||||
|
// .body(body)
|
||||||
|
// .unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_chunk_stream(
|
fn create_chunk_stream(
|
||||||
|
Reference in New Issue
Block a user