diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index 988b53b0..20f1cab4 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -6,19 +6,12 @@ jobs:
matrix:
os: [ubuntu-latest, macOS-latest, windows-latest]
runs-on: ${{ matrix.os }}
-# runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- run: rustup update stable
- - name: Cache cargo build
- uses: actions/cache@v1
- with:
- path: target
- key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
-# key: ubuntu-latest-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
- run: rustup component add rustfmt
- run: rustup component add clippy
- - run: cargo build --all-features
- run: cargo test --all-features
- run: cargo fmt --all -- --check
- run: cargo clippy --all-features --all-targets -- --deny warnings
+ - run: cargo build --all-features
diff --git a/Cargo.lock b/Cargo.lock
index 11dd2afa..d8935839 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -55,6 +55,12 @@ dependencies = [
"memchr",
]
+[[package]]
+name = "bumpalo"
+version = "3.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
+
[[package]]
name = "bytes"
version = "1.1.0"
@@ -184,6 +190,15 @@ dependencies = [
"base64",
]
+[[package]]
+name = "encoding_rs"
+version = "0.8.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b"
+dependencies = [
+ "cfg-if 1.0.0",
+]
+
[[package]]
name = "fastrand"
version = "1.7.0"
@@ -209,6 +224,7 @@ dependencies = [
"openssl",
"rand",
"regex",
+ "reqwest",
"serde",
"serde_json",
"serde_yaml",
@@ -280,6 +296,16 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+[[package]]
+name = "form_urlencoded"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
+dependencies = [
+ "matches",
+ "percent-encoding",
+]
+
[[package]]
name = "fsevent"
version = "0.4.0"
@@ -428,6 +454,25 @@ dependencies = [
"regex",
]
+[[package]]
+name = "h2"
+version = "0.3.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57"
+dependencies = [
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "futures-util",
+ "http",
+ "indexmap",
+ "slab",
+ "tokio",
+ "tokio-util 0.7.2",
+ "tracing",
+]
+
[[package]]
name = "hashbrown"
version = "0.11.2"
@@ -504,6 +549,7 @@ dependencies = [
"futures-channel",
"futures-core",
"futures-util",
+ "h2",
"http",
"http-body",
"httparse",
@@ -517,6 +563,19 @@ dependencies = [
"want",
]
+[[package]]
+name = "hyper-tls"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
+dependencies = [
+ "bytes",
+ "hyper",
+ "native-tls",
+ "tokio",
+ "tokio-native-tls",
+]
+
[[package]]
name = "idna"
version = "0.2.3"
@@ -576,12 +635,27 @@ dependencies = [
"libc",
]
+[[package]]
+name = "ipnet"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b"
+
[[package]]
name = "itoa"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
+[[package]]
+name = "js-sys"
+version = "0.3.57"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397"
+dependencies = [
+ "wasm-bindgen",
+]
+
[[package]]
name = "jsonrpc-core"
version = "18.0.0"
@@ -627,7 +701,7 @@ dependencies = [
"log",
"tokio",
"tokio-stream",
- "tokio-util",
+ "tokio-util 0.6.10",
"unicase",
]
@@ -992,6 +1066,12 @@ dependencies = [
"winapi 0.3.9",
]
+[[package]]
+name = "percent-encoding"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
+
[[package]]
name = "pin-project-lite"
version = "0.2.9"
@@ -1129,6 +1209,42 @@ dependencies = [
"winapi 0.3.9",
]
+[[package]]
+name = "reqwest"
+version = "0.11.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46a1f7aa4f35e5e8b4160449f51afc758f0ce6454315a9fa7d0d113e958c41eb"
+dependencies = [
+ "base64",
+ "bytes",
+ "encoding_rs",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "hyper",
+ "hyper-tls",
+ "ipnet",
+ "js-sys",
+ "lazy_static",
+ "log",
+ "mime",
+ "native-tls",
+ "percent-encoding",
+ "pin-project-lite",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "tokio",
+ "tokio-native-tls",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "winreg",
+]
+
[[package]]
name = "ryu"
version = "1.0.10"
@@ -1214,6 +1330,18 @@ dependencies = [
"serde",
]
+[[package]]
+name = "serde_urlencoded"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
+dependencies = [
+ "form_urlencoded",
+ "itoa",
+ "ryu",
+ "serde",
+]
+
[[package]]
name = "serde_yaml"
version = "0.8.24"
@@ -1373,6 +1501,16 @@ dependencies = [
"winapi 0.3.9",
]
+[[package]]
+name = "tokio-native-tls"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b"
+dependencies = [
+ "native-tls",
+ "tokio",
+]
+
[[package]]
name = "tokio-stream"
version = "0.1.8"
@@ -1398,6 +1536,20 @@ dependencies = [
"tokio",
]
+[[package]]
+name = "tokio-util"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f988a1a1adc2fb21f9c12aa96441da33a1728193ae0b95d2be22dbd17fcb4e5c"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "pin-project-lite",
+ "tokio",
+ "tracing",
+]
+
[[package]]
name = "tower-service"
version = "0.3.1"
@@ -1412,9 +1564,21 @@ checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09"
dependencies = [
"cfg-if 1.0.0",
"pin-project-lite",
+ "tracing-attributes",
"tracing-core",
]
+[[package]]
+name = "tracing-attributes"
+version = "0.1.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "tracing-core"
version = "0.1.26"
@@ -1460,6 +1624,18 @@ dependencies = [
"tinyvec",
]
+[[package]]
+name = "url"
+version = "2.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "matches",
+ "percent-encoding",
+]
+
[[package]]
name = "vcpkg"
version = "0.2.15"
@@ -1505,6 +1681,82 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.80"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad"
+dependencies = [
+ "cfg-if 1.0.0",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.80"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4"
+dependencies = [
+ "bumpalo",
+ "lazy_static",
+ "log",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f741de44b75e14c35df886aff5f1eb73aa114fa5d4d00dcd37b5e01259bf3b2"
+dependencies = [
+ "cfg-if 1.0.0",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.80"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.80"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.80"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744"
+
+[[package]]
+name = "web-sys"
+version = "0.3.57"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
[[package]]
name = "winapi"
version = "0.2.8"
@@ -1591,6 +1843,15 @@ version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
+[[package]]
+name = "winreg"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
+dependencies = [
+ "winapi 0.3.9",
+]
+
[[package]]
name = "ws2_32-sys"
version = "0.2.1"
diff --git a/Cargo.toml b/Cargo.toml
index 168e4292..6bcee844 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -20,6 +20,7 @@ log = "0.4"
notify = "4.0"
rand = "0.8"
regex = "1"
+reqwest = { version = "0.11", features = ["blocking"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_yaml = "0.8"
diff --git a/src/input/playlist.rs b/src/input/playlist.rs
index bc497d66..e7ba909c 100644
--- a/src/input/playlist.rs
+++ b/src/input/playlist.rs
@@ -11,8 +11,8 @@ use serde_json::json;
use simplelog::*;
use crate::utils::{
- check_sync, gen_dummy, get_delta, get_sec, is_close, json_serializer::read_json, modified_time,
- seek_and_length, valid_source, GlobalConfig, Media, PlayoutStatus, DUMMY_LEN,
+ check_sync, gen_dummy, get_delta, get_sec, is_close, is_remote, json_serializer::read_json,
+ modified_time, seek_and_length, valid_source, GlobalConfig, Media, PlayoutStatus, DUMMY_LEN,
};
/// Struct for current playlist.
@@ -77,50 +77,87 @@ impl CurrentProgram {
self.json_path = json.current_file;
self.json_mod = json.modified;
*self.nodes.lock().unwrap() = json.program;
- } else if Path::new(&self.json_path.clone().unwrap()).is_file() {
- let mod_time = modified_time(&self.json_path.clone().unwrap());
+ } else if Path::new(&self.json_path.clone().unwrap()).is_file()
+ || is_remote(&self.json_path.clone().unwrap())
+ {
+ let mut is_playlist_changed = false;
- if let Some(m) = mod_time {
- if !m.to_string().eq(&self.json_mod.clone().unwrap()) {
- // when playlist has changed, reload it
- info!(
- "Reload playlist {}>",
- self.json_path.clone().unwrap()
- );
+ if is_remote(&self.json_path.clone().unwrap()) {
+ let resp = reqwest::blocking::Client::new()
+ .head(self.json_path.clone().unwrap())
+ .send();
+ match resp {
+ Ok(resp) => {
+ if resp.status().is_success() {
+ match resp.headers().get(reqwest::header::LAST_MODIFIED) {
+ Some(last_modified) => {
+ if !last_modified
+ .to_str()
+ .unwrap()
+ .eq(&self.json_mod.clone().unwrap())
+ {
+ is_playlist_changed = true
+ }
+ }
+ None => {}
+ }
+ }
+ }
+ Err(_) => self.on_check_update_error(),
+ };
+ } else {
+ let mod_time = modified_time(&self.json_path.clone().unwrap());
- let json = read_json(
- &self.config,
- self.json_path.clone(),
- self.is_terminated.clone(),
- false,
- 0.0,
- );
-
- self.json_mod = json.modified;
- *self.nodes.lock().unwrap() = json.program;
-
- self.get_current_clip();
- self.index.fetch_add(1, Ordering::SeqCst);
+ if let Some(m) = mod_time {
+ if !m.to_string().eq(&self.json_mod.clone().unwrap()) {
+ is_playlist_changed = true;
+ }
}
}
- } else {
- error!(
- "Playlist {}> not exists!",
- self.json_path.clone().unwrap()
- );
- let mut media = Media::new(0, String::new(), false);
- media.begin = Some(get_sec());
- media.duration = DUMMY_LEN;
- media.out = DUMMY_LEN;
- self.json_path = None;
- *self.nodes.lock().unwrap() = vec![media.clone()];
- self.current_node = media;
- self.playout_stat.list_init.store(true, Ordering::SeqCst);
- self.index.store(0, Ordering::SeqCst);
+ if is_playlist_changed {
+ // when playlist has changed, reload it
+ info!(
+ "Reload playlist {}>",
+ self.json_path.clone().unwrap()
+ );
+
+ let json = read_json(
+ &self.config,
+ self.json_path.clone(),
+ self.is_terminated.clone(),
+ false,
+ 0.0,
+ );
+
+ self.json_mod = json.modified;
+ *self.nodes.lock().unwrap() = json.program;
+
+ self.get_current_clip();
+ self.index.fetch_add(1, Ordering::SeqCst);
+ }
+ } else {
+ self.on_check_update_error();
}
}
+ fn on_check_update_error(&mut self) {
+ error!(
+ "Playlist {}> not exists!",
+ self.json_path.clone().unwrap()
+ );
+ let mut media = Media::new(0, String::new(), false);
+ media.begin = Some(get_sec());
+ media.duration = DUMMY_LEN;
+ media.out = DUMMY_LEN;
+
+ self.json_path = None;
+ *self.nodes.lock().unwrap() = vec![media.clone()];
+ self.current_node = media;
+ self.playout_stat.list_init.store(true, Ordering::SeqCst);
+ self.index.store(0, Ordering::SeqCst);
+ }
+
// Check if day is past and it is time for a new playlist.
fn check_for_next_playlist(&mut self) {
let current_time = get_sec();
diff --git a/src/utils/json_serializer.rs b/src/utils/json_serializer.rs
index 36e504a2..369d82b1 100644
--- a/src/utils/json_serializer.rs
+++ b/src/utils/json_serializer.rs
@@ -8,7 +8,7 @@ use std::{
use simplelog::*;
-use crate::utils::{get_date, modified_time, validate_playlist, GlobalConfig, Media};
+use crate::utils::{get_date, is_remote, modified_time, validate_playlist, GlobalConfig, Media};
pub const DUMMY_LEN: f64 = 60.0;
@@ -75,29 +75,68 @@ pub fn read_json(
current_file = p
}
- if !playlist_path.is_file() {
- error!("Playlist {current_file}> not exists!");
+ let mut playlist: Playlist;
- return Playlist::new(date, start_sec);
+ if is_remote(¤t_file) {
+ let resp = reqwest::blocking::Client::new().get(¤t_file).send();
+
+ match resp {
+ Ok(resp) => {
+ if resp.status().is_success() {
+ info!("Read Remote Playlist: {current_file}>");
+
+ let headers = resp.headers().clone();
+ let body = resp.text().unwrap();
+
+ playlist =
+ serde_json::from_str(&body).expect("Could not read json playlist str.");
+
+ match headers.get(reqwest::header::LAST_MODIFIED) {
+ Some(t) => {
+ playlist.modified = Some(t.to_str().unwrap().to_string());
+ }
+ None => {}
+ }
+ } else {
+ error!(
+ "Get Remote Playlist {current_file}> not success!: {}",
+ resp.text().unwrap()
+ );
+
+ return Playlist::new(date, start_sec);
+ }
+ }
+ Err(e) => {
+ error!("Remote Playlist {current_file}>: {}", e);
+
+ return Playlist::new(date, start_sec);
+ }
+ };
+ } else {
+ if !playlist_path.is_file() {
+ error!("Playlist {current_file}> not exists!");
+
+ return Playlist::new(date, start_sec);
+ }
+
+ info!("Read Playlist: {current_file}>");
+
+ let f = File::options()
+ .read(true)
+ .write(false)
+ .open(¤t_file)
+ .expect("Could not open json playlist file.");
+ playlist = serde_json::from_reader(f).expect("Could not read json playlist file.");
+
+ let modify = modified_time(¤t_file);
+
+ if let Some(modi) = modify {
+ playlist.modified = Some(modi.to_string());
+ }
}
- info!("Read Playlist: {current_file}>");
-
- let f = File::options()
- .read(true)
- .write(false)
- .open(¤t_file)
- .expect("Could not open json playlist file.");
- let mut playlist: Playlist =
- serde_json::from_reader(f).expect("Could not read json playlist file.");
-
- playlist.current_file = Some(current_file.clone());
+ playlist.current_file = Some(current_file);
playlist.start_sec = Some(start_sec);
- let modify = modified_time(¤t_file);
-
- if let Some(modi) = modify {
- playlist.modified = Some(modi.to_string());
- }
// Add extra values to every media clip
for (i, item) in playlist.program.iter_mut().enumerate() {
diff --git a/src/utils/mod.rs b/src/utils/mod.rs
index 36362424..c7a2b8a1 100644
--- a/src/utils/mod.rs
+++ b/src/utils/mod.rs
@@ -429,13 +429,15 @@ pub fn prepare_output_cmd(
cmd
}
+pub fn is_remote(path: &str) -> bool {
+ Regex::new(r"^https?://.*").unwrap().is_match(path)
+}
+
/// Validate input
///
/// Check if input is a remote source, or from storage and see if it exists.
pub fn valid_source(source: &str) -> bool {
- let re = Regex::new(r"^https?://.*").unwrap();
-
- if re.is_match(source) && MediaProbe::new(source).video_streams.is_some() {
+ if is_remote(source) && MediaProbe::new(source).video_streams.is_some() {
return true;
}