diff --git a/Cargo.lock b/Cargo.lock index 1b343565..c6459b6d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,7 +8,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "bytes", "futures-core", "futures-sink", @@ -29,7 +29,7 @@ dependencies = [ "actix-service", "actix-utils", "actix-web", - "bitflags 2.4.2", + "bitflags 2.5.0", "bytes", "derive_more", "futures-core", @@ -53,8 +53,8 @@ dependencies = [ "actix-service", "actix-utils", "ahash", - "base64", - "bitflags 2.4.2", + "base64 0.21.7", + "bitflags 2.5.0", "brotli", "bytes", "bytestring", @@ -63,7 +63,7 @@ dependencies = [ "flate2", "futures-core", "h2", - "http", + "http 0.2.12", "httparse", "httpdate", "itoa", @@ -88,7 +88,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.48", + "syn 2.0.55", ] [[package]] @@ -126,7 +126,7 @@ dependencies = [ "parse-size", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.55", ] [[package]] @@ -136,7 +136,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d22475596539443685426b6bdadb926ad0ecaefdfc5fb05e5e3441f15463c511" dependencies = [ "bytestring", - "http", + "http 0.2.12", "regex", "serde", "tracing", @@ -164,7 +164,7 @@ dependencies = [ "futures-core", "futures-util", "mio", - "socket2 0.5.5", + "socket2 0.5.6", "tokio", "tracing", ] @@ -225,7 +225,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "smallvec", - "socket2 0.5.5", + "socket2 0.5.6", "time", "url", ] @@ -239,7 +239,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.55", ] [[package]] @@ -260,7 +260,7 @@ checksum = "1d613edf08a42ccc6864c941d30fe14e1b676a77d16f1dbadc1174d065a0a775" dependencies = [ "actix-utils", "actix-web", - "base64", + "base64 0.21.7", "futures-core", "futures-util", "log", @@ -296,9 +296,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.8.8" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42cd52102d3df161c77a887b608d7a4897d7cc112886a9537b738a887a03aaff" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "getrandom", @@ -309,9 +309,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -354,9 +354,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.11" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" dependencies = [ "anstyle", "anstyle-parse", @@ -452,7 +452,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3" dependencies = [ "concurrent-queue", - "event-listener 5.0.0", + "event-listener 5.2.0", "event-listener-strategy 0.5.0", "futures-core", "pin-project-lite", @@ -467,8 +467,8 @@ dependencies = [ "async-lock 3.3.0", "async-task", "concurrent-queue", - "fastrand 2.0.1", - "futures-lite 2.2.0", + "fastrand 2.0.2", + "futures-lite 2.3.0", "slab", ] @@ -480,10 +480,10 @@ checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ "async-channel 2.2.0", "async-executor", - "async-io 2.3.1", + "async-io 2.3.2", "async-lock 3.3.0", "blocking", - "futures-lite 2.2.0", + "futures-lite 2.3.0", "once_cell", ] @@ -509,18 +509,18 @@ dependencies = [ [[package]] name = "async-io" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f97ab0c5b00a7cdbe5a371b9a782ee7be1316095885c8a4ea1daf490eb0ef65" +checksum = "dcccb0f599cfa2f8ace422d3555572f47424da5648a4382a9dd0310ff8210884" dependencies = [ "async-lock 3.3.0", "cfg-if", "concurrent-queue", "futures-io", - "futures-lite 2.2.0", + "futures-lite 2.3.0", "parking", - "polling 3.4.0", - "rustix 0.38.31", + "polling 3.6.0", + "rustix 0.38.32", "slab", "tracing", "windows-sys 0.52.0", @@ -581,13 +581,13 @@ checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799" [[package]] name = "async-trait" -version = "0.1.77" +version = "0.1.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.55", ] [[package]] @@ -618,27 +618,17 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" -[[package]] -name = "atomic-write-file" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edcdbedc2236483ab103a53415653d6b4442ea6141baf1ffa85df29635e88436" -dependencies = [ - "nix", - "rand", -] - [[package]] name = "autocfg" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", @@ -655,6 +645,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" + [[package]] name = "base64ct" version = "1.6.0" @@ -669,9 +665,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" dependencies = [ "serde", ] @@ -703,18 +699,18 @@ dependencies = [ "async-channel 2.2.0", "async-lock 3.3.0", "async-task", - "fastrand 2.0.1", + "fastrand 2.0.2", "futures-io", - "futures-lite 2.2.0", + "futures-lite 2.3.0", "piper", "tracing", ] [[package]] name = "brotli" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "516074a47ef4bce09577a3b379392300159ce5b1ba2e501ff1c819950066100f" +checksum = "d640d25bc63c50fb1f0b545ffd80207d2e10a4c965530809b40ba3386825c391" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -733,9 +729,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" [[package]] name = "byteorder" @@ -745,9 +741,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "bytestring" @@ -760,9 +756,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.83" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" dependencies = [ "jobserver", "libc", @@ -786,9 +782,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.34" +version = "0.4.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" +checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a" dependencies = [ "android-tzdata", "iana-time-zone", @@ -796,7 +792,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.0", + "windows-targets 0.52.4", ] [[package]] @@ -817,9 +813,9 @@ checksum = "6e4de3bc4ea267985becf712dc6d9eed8b04c953b3fcfb339ebc87acd9804901" [[package]] name = "clap" -version = "4.5.0" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", "clap_derive", @@ -827,9 +823,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.0" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ "anstream", "anstyle", @@ -839,14 +835,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.0" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ - "heck", + "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.55", ] [[package]] @@ -893,16 +889,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "core-foundation-sys" version = "0.8.6" @@ -935,18 +921,18 @@ checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-channel" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" dependencies = [ "crossbeam-utils", ] @@ -997,9 +983,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.5" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc5d6b04b3fd0ba9926f945895de7d806260a2d7431ba82e7edaecb043c4c6b8" +checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" dependencies = [ "darling_core", "darling_macro", @@ -1007,27 +993,27 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.5" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04e48a959bcd5c761246f5d090ebc2fbf7b9cd527a492b07a67510c108f1e7e3" +checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.48", + "syn 2.0.55", ] [[package]] name = "darling_macro" -version = "0.20.5" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1545d67a2149e1d93b7e5c7752dce5a7426eb5d1357ddcfd89336b94444f77" +checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ "darling_core", "quote", - "syn 2.0.48", + "syn 2.0.55", ] [[package]] @@ -1105,11 +1091,11 @@ dependencies = [ [[package]] name = "email-encoding" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbfb21b9878cf7a348dcb8559109aabc0ec40d69924bd706fa5149846c4fef75" +checksum = "a87260449b06739ee78d6281c68d2a0ff3e3af64a78df63d3a1aeb3c06997c8a" dependencies = [ - "base64", + "base64 0.22.0", "memchr", ] @@ -1174,9 +1160,9 @@ dependencies = [ [[package]] name = "event-listener" -version = "5.0.0" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b72557800024fabbaa2449dd4bf24e37b93702d457a4d4f2b0dd1f0f039f20c1" +checksum = "2b5fb89194fa3cad959b833185b3063ba881dbfc7030680b314250779fb4cc91" dependencies = [ "concurrent-queue", "parking", @@ -1199,7 +1185,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "feedafcaa9b749175d5ac357452a9d41ea2911da598fde46ce1fe02c37751291" dependencies = [ - "event-listener 5.0.0", + "event-listener 5.2.0", "pin-project-lite", ] @@ -1225,13 +1211,13 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" [[package]] name = "ffplayout" -version = "0.20.5" +version = "0.21.0-beta1" dependencies = [ "chrono", "clap", @@ -1253,7 +1239,7 @@ dependencies = [ [[package]] name = "ffplayout-api" -version = "0.20.5" +version = "0.21.0-beta1" dependencies = [ "actix-files", "actix-multipart", @@ -1292,13 +1278,14 @@ dependencies = [ [[package]] name = "ffplayout-lib" -version = "0.20.5" +version = "0.21.0-beta1" dependencies = [ "chrono", "crossbeam-channel", "derive_more", "ffprobe", "file-rotate", + "lazy_static", "lettre", "lexical-sort", "log", @@ -1485,11 +1472,11 @@ dependencies = [ [[package]] name = "futures-lite" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445ba825b27408685aaecefd65178908c36c6e96aaf6d8599419d46e624192ba" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ - "fastrand 2.0.1", + "fastrand 2.0.2", "futures-core", "futures-io", "parking", @@ -1504,7 +1491,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.55", ] [[package]] @@ -1586,16 +1573,16 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb" dependencies = [ "bytes", "fnv", "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.12", "indexmap", "slab", "tokio", @@ -1632,10 +1619,16 @@ dependencies = [ ] [[package]] -name = "hermit-abi" -version = "0.3.5" +name = "heck" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -1672,9 +1665,20 @@ dependencies = [ [[package]] name = "http" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" dependencies = [ "bytes", "fnv", @@ -1683,12 +1687,24 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" dependencies = [ "bytes", - "http", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +dependencies = [ + "bytes", + "futures-core", + "http 1.1.0", + "http-body", "pin-project-lite", ] @@ -1712,40 +1728,58 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.28" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a" dependencies = [ "bytes", "futures-channel", - "futures-core", "futures-util", - "h2", - "http", + "http 1.1.0", "http-body", "httparse", - "httpdate", "itoa", "pin-project-lite", - "socket2 0.5.5", + "smallvec", "tokio", - "tower-service", - "tracing", "want", ] [[package]] name = "hyper-rustls" -version = "0.24.2" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" dependencies = [ "futures-util", - "http", + "http 1.1.0", "hyper", - "rustls 0.21.10", + "hyper-util", + "rustls 0.22.3", + "rustls-pki-types", "tokio", "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body", + "hyper", + "pin-project-lite", + "socket2 0.5.6", + "tokio", + "tower", + "tower-service", + "tracing", ] [[package]] @@ -1789,9 +1823,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.3" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown", @@ -1854,9 +1888,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jobserver" @@ -1869,20 +1903,20 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] [[package]] name = "jsonwebtoken" -version = "9.2.0" +version = "9.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7ea04a7c5c055c175f189b6dc6ba036fd62306b58c66c9f6389036c503a3f4" +checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f" dependencies = [ - "base64", + "base64 0.21.7", "js-sys", "pem", "ring", @@ -1937,27 +1971,27 @@ dependencies = [ [[package]] name = "lettre" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357ff5edb6d8326473a64c82cf41ddf78ab116f89668c50c4fac1b321e5e80f4" +checksum = "8305b122b8ccc64e437b0de101851f9f00aade5886246e85f341c1d9a15a91b7" dependencies = [ - "base64", + "base64 0.22.0", "chumsky", "email-encoding", "email_address", - "fastrand 2.0.1", + "fastrand 2.0.2", "httpdate", "idna", "mime", "nom", "percent-encoding", "quoted_printable", - "rustls 0.22.2", - "rustls-pemfile 2.0.0", - "socket2 0.5.5", + "rustls 0.23.4", + "rustls-pemfile 2.1.1", + "socket2 0.5.6", "tokio", "url", - "webpki-roots 0.26.1", + "webpki-roots", ] [[package]] @@ -2017,9 +2051,9 @@ dependencies = [ [[package]] name = "local-ip-address" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63e1499d2495be571af92e9ca9dca4e7bf26c47b87cb8d0c6100825e521dd6b" +checksum = "136ef34e18462b17bf39a7826f8f3bbc223341f8e83822beb8b77db9a3d49696" dependencies = [ "libc", "neli", @@ -2045,9 +2079,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" dependencies = [ "value-bag", ] @@ -2136,17 +2170,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "nix" -version = "0.27.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" -dependencies = [ - "bitflags 2.4.2", - "cfg-if", - "libc", -] - [[package]] name = "nom" version = "7.1.3" @@ -2163,7 +2186,7 @@ version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "crossbeam-channel", "filetime", "fsevent-sys", @@ -2274,9 +2297,9 @@ dependencies = [ [[package]] name = "num_threads" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" dependencies = [ "libc", ] @@ -2381,7 +2404,7 @@ version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b8fcc794035347fb64beda2d3b462595dd2753e3f268d89c5aae77e8cf2c310" dependencies = [ - "base64", + "base64 0.21.7", "serde", ] @@ -2400,6 +2423,26 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -2419,7 +2462,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" dependencies = [ "atomic-waker", - "fastrand 2.0.1", + "fastrand 2.0.2", "futures-io", ] @@ -2446,9 +2489,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "polling" @@ -2468,14 +2511,15 @@ dependencies = [ [[package]] name = "polling" -version = "3.4.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30054e72317ab98eddd8561db0f6524df3367636884b7b21b703e4b280a84a14" +checksum = "e0c976a60b2d7e99d6f229e414670a9b85d13ac305cc6d1e9c134de58c5aaaf6" dependencies = [ "cfg-if", "concurrent-queue", + "hermit-abi", "pin-project-lite", - "rustix 0.38.31", + "rustix 0.38.32", "tracing", "windows-sys 0.52.0", ] @@ -2494,9 +2538,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -2510,7 +2554,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.55", ] [[package]] @@ -2569,9 +2613,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.8.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -2598,9 +2642,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.3" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", @@ -2610,9 +2654,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", @@ -2621,9 +2665,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "relative-path" @@ -2633,20 +2677,21 @@ checksum = "e898588f33fdd5b9420719948f9f2a32c922a246964576f71ba7f24f80610fbc" [[package]] name = "reqwest" -version = "0.11.24" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" +checksum = "2d66674f2b6fb864665eea7a3c1ac4e3dfacd2fda83cf6f935a612e01b0e3338" dependencies = [ - "base64", + "base64 0.21.7", "bytes", - "encoding_rs", + "futures-channel", "futures-core", "futures-util", - "h2", - "http", + "http 1.1.0", "http-body", + "http-body-util", "hyper", "hyper-rustls", + "hyper-util", "ipnet", "js-sys", "log", @@ -2654,13 +2699,13 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls 0.21.10", + "rustls 0.22.3", "rustls-pemfile 1.0.4", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", - "system-configuration", "tokio", "tokio-rustls", "tower-service", @@ -2668,22 +2713,23 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 0.25.4", + "webpki-roots", "winreg", ] [[package]] name = "ring" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", + "cfg-if", "getrandom", "libc", "spin 0.9.8", "untrusted", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2758,11 +2804,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.31" +version = "0.38.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "errno", "libc", "linux-raw-sys 0.4.13", @@ -2771,26 +2817,29 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.10" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" -dependencies = [ - "log", - "ring", - "rustls-webpki 0.101.7", - "sct", -] - -[[package]] -name = "rustls" -version = "0.22.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41" +checksum = "99008d7ad0bbbea527ec27bddbc0e432c5b87d8175178cee68d2eec9c4a1813c" dependencies = [ "log", "ring", "rustls-pki-types", - "rustls-webpki 0.102.2", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c4d6d8ad9f2492485e13453acbb291dd08f64441b6609c491f1c2cd2c6b4fe1" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", "subtle", "zeroize", ] @@ -2801,34 +2850,24 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64", + "base64 0.21.7", ] [[package]] name = "rustls-pemfile" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e4980fa29e4c4b212ffb3db068a564cbf560e51d3944b7c88bd8bf5bec64f4" +checksum = "f48172685e6ff52a556baa527774f61fcaa884f59daf3375c62a3f1cd2549dab" dependencies = [ - "base64", + "base64 0.21.7", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.2.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a716eb65e3158e90e17cd93d855216e27bde02745ab842f2cab4a39dba1bacf" - -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring", - "untrusted", -] +checksum = "868e20fada228fefaf6b652e00cc73623d54f8171e7352c18bb281571f2d92da" [[package]] name = "rustls-webpki" @@ -2843,9 +2882,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "same-file" @@ -2872,47 +2911,37 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "semver" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" [[package]] name = "serde" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.55", ] [[package]] name = "serde_json" -version = "1.0.113" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" dependencies = [ "itoa", "ryu", @@ -2942,9 +2971,9 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.31" +version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adf8a49373e98a4c5f0ceb5d05aa7c648d75f63774981ed95b7c7443bbd50c6e" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ "indexmap", "itoa", @@ -2975,7 +3004,7 @@ checksum = "b93fb4adc70021ac1b47f7d45e8cc4169baaa7ea58483bc5b721d19a26202212" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.55", ] [[package]] @@ -3045,9 +3074,9 @@ dependencies = [ [[package]] name = "simplelog" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acee08041c5de3d5048c8b3f6f13fafb3026b24ba43c6a695a0c76179b844369" +checksum = "16257adbfaef1ee58b1363bdc0664c9b8e1e30aed86049635fb5f147d065a9c0" dependencies = [ "log", "paris", @@ -3066,9 +3095,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" @@ -3082,12 +3111,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -3128,9 +3157,9 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dba03c279da73694ef99763320dea58b51095dfe87d001b1d4b5fe78ba8763cf" +checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa" dependencies = [ "sqlx-core", "sqlx-macros", @@ -3141,9 +3170,9 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd" +checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6" dependencies = [ "ahash", "atoi", @@ -3151,7 +3180,6 @@ dependencies = [ "bytes", "crc", "crossbeam-queue", - "dotenvy", "either", "event-listener 2.5.3", "futures-channel", @@ -3181,9 +3209,9 @@ dependencies = [ [[package]] name = "sqlx-macros" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89961c00dc4d7dffb7aee214964b065072bff69e36ddb9e2c107541f75e4f2a5" +checksum = "4ea40e2345eb2faa9e1e5e326db8c34711317d2b5e08d0d5741619048a803127" dependencies = [ "proc-macro2", "quote", @@ -3194,14 +3222,13 @@ dependencies = [ [[package]] name = "sqlx-macros-core" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0bd4519486723648186a08785143599760f7cc81c52334a55d6a83ea1e20841" +checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8" dependencies = [ - "atomic-write-file", "dotenvy", "either", - "heck", + "heck 0.4.1", "hex", "once_cell", "proc-macro2", @@ -3220,13 +3247,13 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4" +checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" dependencies = [ "atoi", - "base64", - "bitflags 2.4.2", + "base64 0.21.7", + "bitflags 2.5.0", "byteorder", "bytes", "crc", @@ -3262,13 +3289,13 @@ dependencies = [ [[package]] name = "sqlx-postgres" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24" +checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" dependencies = [ "atoi", - "base64", - "bitflags 2.4.2", + "base64 0.21.7", + "bitflags 2.5.0", "byteorder", "crc", "dotenvy", @@ -3289,7 +3316,6 @@ dependencies = [ "rand", "serde", "serde_json", - "sha1", "sha2", "smallvec", "sqlx-core", @@ -3301,9 +3327,9 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "210976b7d948c7ba9fced8ca835b11cbb2d677c59c79de41ac0d397e14547490" +checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa" dependencies = [ "atoi", "flume", @@ -3388,9 +3414,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" dependencies = [ "proc-macro2", "quote", @@ -3405,9 +3431,9 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "sysinfo" -version = "0.30.5" +version = "0.30.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb4f3438c8f6389c864e61221cbc97e9bca98b4daf39a5beb7bea660f528bb2" +checksum = "0c385888ef380a852a16209afc8cfad22795dd8873d69c9a14d2e2088f118d18" dependencies = [ "cfg-if", "core-foundation-sys", @@ -3418,51 +3444,30 @@ dependencies = [ "windows", ] -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "tempfile" -version = "3.10.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", - "fastrand 2.0.1", - "rustix 0.38.31", + "fastrand 2.0.2", + "rustix 0.38.32", "windows-sys 0.52.0", ] [[package]] name = "termcolor" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] [[package]] name = "tests" -version = "0.20.5" +version = "0.21.0-beta1" dependencies = [ "chrono", "crossbeam-channel", @@ -3487,22 +3492,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.55", ] [[package]] @@ -3579,7 +3584,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.5", + "socket2 0.5.6", "tokio-macros", "windows-sys 0.48.0", ] @@ -3592,24 +3597,25 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.55", ] [[package]] name = "tokio-rustls" -version = "0.24.1" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" dependencies = [ - "rustls 0.21.10", + "rustls 0.22.3", + "rustls-pki-types", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ "futures-core", "pin-project-lite", @@ -3630,6 +3636,28 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + [[package]] name = "tower-service" version = "0.3.2" @@ -3656,7 +3684,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.55", ] [[package]] @@ -3703,9 +3731,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] @@ -3724,9 +3752,9 @@ checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" [[package]] name = "unsafe-libyaml" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] name = "untrusted" @@ -3759,9 +3787,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ "getrandom", ] @@ -3774,9 +3802,9 @@ checksum = "4e8257fbc510f0a46eb602c10215901938b5c2a7d5e70fc11483b1d3c9b5b18c" [[package]] name = "value-bag" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126e423afe2dd9ac52142e7e9d5ce4135d7e13776c529d27fd6bc49f19e3280b" +checksum = "74797339c3b98616c009c7c3eb53a0ce41e85c8ec66bd3db96ed132d20cfdee8" [[package]] name = "vcpkg" @@ -3798,9 +3826,9 @@ checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -3822,10 +3850,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] -name = "wasm-bindgen" -version = "0.2.91" +name = "wasite" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3833,24 +3867,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.55", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if", "js-sys", @@ -3860,9 +3894,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3870,39 +3904,33 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.55", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "web-sys" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", ] -[[package]] -name = "webpki-roots" -version = "0.25.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" - [[package]] name = "webpki-roots" version = "0.26.1" @@ -3914,9 +3942,13 @@ dependencies = [ [[package]] name = "whoami" -version = "1.4.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" +checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" +dependencies = [ + "redox_syscall", + "wasite", +] [[package]] name = "winapi" @@ -3956,7 +3988,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ "windows-core", - "windows-targets 0.52.0", + "windows-targets 0.52.4", ] [[package]] @@ -3965,7 +3997,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.4", ] [[package]] @@ -3983,7 +4015,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.4", ] [[package]] @@ -4003,17 +4035,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", ] [[package]] @@ -4024,9 +4056,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" @@ -4036,9 +4068,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" @@ -4048,9 +4080,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" @@ -4060,9 +4092,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" @@ -4072,9 +4104,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" [[package]] name = "windows_x86_64_gnullvm" @@ -4084,9 +4116,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" [[package]] name = "windows_x86_64_msvc" @@ -4096,9 +4128,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" [[package]] name = "winreg" @@ -4127,7 +4159,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.55", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 24a15de6..c6f2faf5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ default-members = ["ffplayout-api", "ffplayout-engine", "tests"] resolver = "2" [workspace.package] -version = "0.20.5" +version = "0.21.0-beta1" license = "GPL-3.0" repository = "https://github.com/ffplayout/ffplayout" authors = ["Jonathan Baecker "] diff --git a/assets/advanced.yml b/assets/advanced.yml new file mode 100644 index 00000000..b0f80a08 --- /dev/null +++ b/assets/advanced.yml @@ -0,0 +1,30 @@ +help: Changing these settings is for advanced users only! There will be no support or guarantee that it will be stable after changing them. +decoder: + input_param: + # output_param get also applied to ingest instance. + output_param: + filters: + deinterlace: # yadif=0:-1:0 + pad_scale_w: # scale={}:-1, + pad_scale_h: # scale=-1:{}, + pad_video: # '{}pad=max(iw\\,ih*({0}/{1})):ow/({0}/{1}):(ow-iw)/2:(oh-ih)/2' + fps: # fps={} + scale: # scale={}:{} + set_dar: # setdar=dar={} + fade_in: # '{}fade=in:st=0:d=0.5' + fade_out: # '{}fade=out:st={}:d=1.0' + overlay_logo_scale: # ',scale={}' + overlay_logo: # null[v];movie={}:loop=0,setpts=N/(FRAME_RATE*TB),format=rgba,colorchannelmixer=aa={}{}[l];[v][l]{}:shortest=1 + overlay_logo_fade_in: # ',fade=in:st=0:d=1.0:alpha=1' + overlay_logo_fade_out: # ',fade=out:st={}:d=1.0:alpha=1' + tpad: # tpad=stop_mode=add:stop_duration={} + drawtext_from_file: # drawtext=text='{}':{}{} + drawtext_from_zmq: # zmq=b=tcp\\\\://'{}',drawtext@dyntext={} + aevalsrc: # aevalsrc=0:channel_layout=stereo:duration={}:sample_rate=48000 + apad: # apad=whole_dur={} + volume: # volume={} + split: # split={}{} +encoder: + input_param: +ingest: + input_param: diff --git a/assets/ffplayout.yml b/assets/ffplayout.yml index b6bcc087..08e4b9f1 100644 --- a/assets/ffplayout.yml +++ b/assets/ffplayout.yml @@ -34,7 +34,7 @@ logging: 'backup_count' says how long log files will be saved in days. 'local_time' to false will set log timestamps to UTC. Path to /var/log/ only if you run this program as daemon. 'level' can be DEBUG, INFO, WARNING, ERROR. - 'ffmpeg_level' can be info, warning, error. + 'ffmpeg_level/ingest_level' can be info, warning, error. 'detect_silence' logs an error message if the audio line is silent for 15 seconds during the validation process. log_to_file: true diff --git a/ffplayout-api/Cargo.toml b/ffplayout-api/Cargo.toml index d18368a3..50978ed2 100644 --- a/ffplayout-api/Cargo.toml +++ b/ffplayout-api/Cargo.toml @@ -35,7 +35,7 @@ path-clean = "1.0" rand = "0.8" regex = "1" relative-path = "1.8" -reqwest = { version = "0.11", default-features = false, features = ["blocking", "json", "rustls-tls"] } +reqwest = { version = "0.12", default-features = false, features = ["blocking", "json", "rustls-tls"] } rpassword = "7.2" sanitize-filename = "0.5" serde = { version = "1.0", features = ["derive"] } diff --git a/ffplayout-api/src/api/auth.rs b/ffplayout-api/src/api/auth.rs index 4aa68bec..9c933a68 100644 --- a/ffplayout-api/src/api/auth.rs +++ b/ffplayout-api/src/api/auth.rs @@ -1,6 +1,6 @@ use actix_web::error::ErrorUnauthorized; use actix_web::Error; -use chrono::{Duration, Utc}; +use chrono::{TimeDelta, Utc}; use jsonwebtoken::{self, DecodingKey, EncodingKey, Header, Validation}; use serde::{Deserialize, Serialize}; @@ -23,7 +23,7 @@ impl Claims { id, username, role, - exp: (Utc::now() + Duration::days(JWT_EXPIRATION_DAYS)).timestamp(), + exp: (Utc::now() + TimeDelta::try_days(JWT_EXPIRATION_DAYS).unwrap()).timestamp(), } } } diff --git a/ffplayout-api/src/api/routes.rs b/ffplayout-api/src/api/routes.rs index 1512b58b..407a220c 100644 --- a/ffplayout-api/src/api/routes.rs +++ b/ffplayout-api/src/api/routes.rs @@ -26,7 +26,7 @@ use argon2::{ password_hash::{rand_core::OsRng, PasswordHash, SaltString}, Argon2, PasswordHasher, PasswordVerifier, }; -use chrono::{DateTime, Datelike, Duration, Local, NaiveDateTime, TimeZone, Utc}; +use chrono::{DateTime, Datelike, Local, NaiveDateTime, TimeDelta, TimeZone, Utc}; use path_clean::PathClean; use regex::Regex; use serde::{Deserialize, Serialize}; @@ -817,7 +817,7 @@ pub async fn save_playlist( data: web::Json, ) -> Result { match write_playlist(&pool.into_inner(), *id, data.into_inner()).await { - Ok(res) => Ok(res), + Ok(res) => Ok(web::Json(res)), Err(e) => Err(e), } } @@ -885,7 +885,7 @@ pub async fn del_playlist( params: web::Path<(i32, String)>, ) -> Result { match delete_playlist(&pool.into_inner(), params.0, ¶ms.1).await { - Ok(_) => Ok(format!("Delete playlist from {} success!", params.1)), + Ok(m) => Ok(web::Json(m)), Err(e) => Err(e), } } @@ -1149,7 +1149,7 @@ async fn get_program( } let date_range = get_date_range(&vec_strings![ - (after - Duration::days(days)).format("%Y-%m-%d"), + (after - TimeDelta::try_days(days).unwrap_or_default()).format("%Y-%m-%d"), "-", before.format("%Y-%m-%d") ]); @@ -1194,7 +1194,8 @@ async fn get_program( program.push(p_item); } - naive += Duration::milliseconds(((item.out - item.seek) * 1000.0) as i64); + naive += TimeDelta::try_milliseconds(((item.out - item.seek) * 1000.0) as i64) + .unwrap_or_default(); } } diff --git a/ffplayout-api/src/utils/playlist.rs b/ffplayout-api/src/utils/playlist.rs index fcbd8b96..55022843 100644 --- a/ffplayout-api/src/utils/playlist.rs +++ b/ffplayout-api/src/utils/playlist.rs @@ -114,7 +114,11 @@ pub async fn generate_playlist( } } -pub async fn delete_playlist(conn: &Pool, id: i32, date: &str) -> Result<(), ServiceError> { +pub async fn delete_playlist( + conn: &Pool, + id: i32, + date: &str, +) -> Result { let (config, _) = playout_config(conn, &id).await?; let mut playlist_path = PathBuf::from(&config.playlist.path); let d: Vec<&str> = date.split('-').collect(); @@ -125,11 +129,14 @@ pub async fn delete_playlist(conn: &Pool, id: i32, date: &str) -> Result .with_extension("json"); if playlist_path.is_file() { - if let Err(e) = fs::remove_file(playlist_path) { - error!("{e}"); - return Err(ServiceError::InternalServerError); - }; + match fs::remove_file(playlist_path) { + Ok(_) => Ok(format!("Delete playlist from {date} success!")), + Err(e) => { + error!("{e}"); + Err(ServiceError::InternalServerError) + } + } + } else { + Ok(format!("No playlist to delete on: {date}")) } - - Ok(()) } diff --git a/ffplayout-engine/Cargo.toml b/ffplayout-engine/Cargo.toml index 75089335..384b6e1e 100644 --- a/ffplayout-engine/Cargo.toml +++ b/ffplayout-engine/Cargo.toml @@ -21,7 +21,7 @@ notify = "6.0" notify-debouncer-full = { version = "*", default-features = false } rand = "0.8" regex = "1" -reqwest = { version = "0.11", default-features = false, features = ["blocking", "json", "rustls-tls"] } +reqwest = { version = "0.12", default-features = false, features = ["blocking", "json", "rustls-tls"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" simplelog = { version = "0.12", features = ["paris"] } @@ -77,6 +77,11 @@ assets = [ "/etc/sudoers.d/", "644", ], + [ + "../assets/advanced.yml", + "/etc/ffplayout/", + "644", + ], [ "../assets/ffplayout.yml", "/etc/ffplayout/", @@ -153,6 +158,11 @@ assets = [ "/etc/ffplayout/", "644", ], + [ + "../assets/advanced.yml", + "/etc/ffplayout/", + "644", + ], [ "../assets/logo.png", "/usr/share/ffplayout/", @@ -192,6 +202,7 @@ license = "GPL-3.0" assets = [ { source = "../target/x86_64-unknown-linux-musl/release/ffpapi", dest = "/usr/bin/ffpapi", mode = "755" }, { source = "../target/x86_64-unknown-linux-musl/release/ffplayout", dest = "/usr/bin/ffplayout", mode = "755" }, + { source = "../assets/advanced.yml", dest = "/etc/ffplayout/advanced.yml", mode = "644", config = true }, { source = "../assets/ffplayout.yml", dest = "/etc/ffplayout/ffplayout.yml", mode = "644", config = true }, { source = "../assets/ffpapi.service", dest = "/lib/systemd/system/ffpapi.service", mode = "644" }, { source = "../assets/ffplayout.service", dest = "/lib/systemd/system/ffplayout.service", mode = "644" }, diff --git a/ffplayout-engine/src/input/ingest.rs b/ffplayout-engine/src/input/ingest.rs index d45b74c6..c2db4c4e 100644 --- a/ffplayout-engine/src/input/ingest.rs +++ b/ffplayout-engine/src/input/ingest.rs @@ -14,7 +14,7 @@ use ffplayout_lib::{ controller::ProcessUnit::*, test_tcp_port, Media, PlayoutConfig, ProcessControl, FFMPEG_IGNORE_ERRORS, FFMPEG_UNRECOVERABLE_ERRORS, }, - vec_strings, + vec_strings, ADVANCED_CONFIG, }; fn server_monitor( @@ -61,6 +61,10 @@ pub fn ingest_server( dummy_media.unit = Ingest; dummy_media.add_filter(&config, &None); + if let Some(ingest_input_cmd) = &ADVANCED_CONFIG.ingest.input_cmd { + server_cmd.append(&mut ingest_input_cmd.clone()); + } + server_cmd.append(&mut stream_input.clone()); if let Some(mut filter) = dummy_media.filter { diff --git a/ffplayout-engine/src/input/playlist.rs b/ffplayout-engine/src/input/playlist.rs index a66af059..a87fe01e 100644 --- a/ffplayout-engine/src/input/playlist.rs +++ b/ffplayout-engine/src/input/playlist.rs @@ -11,9 +11,11 @@ use serde_json::json; use simplelog::*; use ffplayout_lib::utils::{ - controller::PlayerControl, gen_dummy, get_delta, is_close, is_remote, - json_serializer::read_json, loop_filler, loop_image, modified_time, seek_and_length, - time_in_seconds, Media, MediaProbe, PlayoutConfig, PlayoutStatus, IMAGE_FORMAT, + controller::PlayerControl, + gen_dummy, get_delta, is_close, is_remote, + json_serializer::{read_json, set_defaults}, + loop_filler, loop_image, modified_time, seek_and_length, time_in_seconds, JsonPlaylist, Media, + MediaProbe, PlayoutConfig, PlayoutStatus, IMAGE_FORMAT, }; /// Struct for current playlist. @@ -24,9 +26,7 @@ pub struct CurrentProgram { config: PlayoutConfig, start_sec: f64, end_sec: f64, - json_mod: Option, - json_path: Option, - json_date: String, + json_playlist: JsonPlaylist, player_control: PlayerControl, current_node: Media, is_terminated: Arc, @@ -47,9 +47,10 @@ impl CurrentProgram { config: config.clone(), start_sec: config.playlist.start_sec.unwrap(), end_sec: config.playlist.length_sec.unwrap(), - json_mod: None, - json_path: None, - json_date: String::new(), + json_playlist: JsonPlaylist::new( + "1970-01-01".to_string(), + config.playlist.start_sec.unwrap(), + ), player_control: player_control.clone(), current_node: Media::new(0, "", false), is_terminated, @@ -65,9 +66,9 @@ impl CurrentProgram { let mut get_current = false; let mut reload = false; - if let Some(path) = self.json_path.clone() { + if let Some(path) = self.json_playlist.path.clone() { if (Path::new(&path).is_file() || is_remote(&path)) - && self.json_mod != modified_time(&path) + && self.json_playlist.modified != modified_time(&path) { info!("Reload playlist {path}"); self.playout_stat.list_init.store(true, Ordering::SeqCst); @@ -79,26 +80,24 @@ impl CurrentProgram { } if get_current { - let json = read_json( - &self.config, + self.json_playlist = read_json( + &mut self.config, &self.player_control, - self.json_path.clone(), + self.json_playlist.path.clone(), self.is_terminated.clone(), seek, false, ); if !reload { - if let Some(file) = &json.current_file { + if let Some(file) = &self.json_playlist.path { info!("Read playlist: {file}"); } } - self.json_path = json.current_file; - self.json_mod = json.modified; - *self.player_control.current_list.lock().unwrap() = json.program; + *self.player_control.current_list.lock().unwrap() = self.json_playlist.program.clone(); - if self.json_path.is_none() { + if self.json_playlist.path.is_none() { trace!("missing playlist"); self.current_node = Media::new(0, "", false); @@ -137,15 +136,16 @@ impl CurrentProgram { trace!("next_start: {next_start}, end_sec: {}", self.end_sec); // Check if we over the target length or we are close to it, if so we load the next playlist. - if next_start >= self.end_sec - || is_close(total_delta, 0.0, 2.0) - || is_close(total_delta, self.end_sec, 2.0) + if !self.config.playlist.infinit + && (next_start >= self.end_sec + || is_close(total_delta, 0.0, 2.0) + || is_close(total_delta, self.end_sec, 2.0)) { trace!("get next day"); next = true; - let json = read_json( - &self.config, + self.json_playlist = read_json( + &mut self.config, &self.player_control, None, self.is_terminated.clone(), @@ -153,18 +153,14 @@ impl CurrentProgram { true, ); - if let Some(file) = &json.current_file { + if let Some(file) = &self.json_playlist.path { info!("Read next playlist: {file}"); } self.playout_stat.list_init.store(false, Ordering::SeqCst); - self.set_status(json.date.clone()); + self.set_status(self.json_playlist.date.clone()); - self.json_path = json.current_file.clone(); - self.json_mod = json.modified; - self.json_date = json.date; - - *self.player_control.current_list.lock().unwrap() = json.program; + *self.player_control.current_list.lock().unwrap() = self.json_playlist.program.clone(); self.player_control.current_index.store(0, Ordering::SeqCst); } else { self.load_or_update_playlist(seek) @@ -212,7 +208,7 @@ impl CurrentProgram { let mut time_sec = time_in_seconds(); if time_sec < self.start_sec { - time_sec += self.config.playlist.length_sec.unwrap() + time_sec += 86400.0 // self.config.playlist.length_sec.unwrap(); } time_sec @@ -231,6 +227,15 @@ impl CurrentProgram { time_sec += *shift; } + drop(shift); + + if self.config.playlist.infinit + && self.json_playlist.length.unwrap() < 86400.0 + && time_sec > self.json_playlist.length.unwrap() + self.start_sec + { + self.recalculate_begin(true) + } + for (i, item) in self .player_control .current_list @@ -266,14 +271,14 @@ impl CurrentProgram { // de-instance node to preserve original values in list let mut node_clone = nodes[index].clone(); + // Important! When no manual drop is happen here, lock is still active in handle_list_init + drop(nodes); + trace!("Clip from init: {}", node_clone.source); node_clone.seek += time_sec - (node_clone.begin.unwrap() - *self.playout_stat.time_shift.lock().unwrap()); - // Important! When no manual drop is happen here, lock is still active in handle_list_init - drop(nodes); - self.current_node = handle_list_init( &self.config, node_clone, @@ -297,7 +302,6 @@ impl CurrentProgram { fn fill_end(&mut self, total_delta: f64) { // Fill end from playlist - let index = self.player_control.current_index.load(Ordering::SeqCst); let mut media = Media::new(index, "", false); media.begin = Some(time_in_seconds()); @@ -327,6 +331,20 @@ impl CurrentProgram { .current_index .fetch_add(1, Ordering::SeqCst); } + + fn recalculate_begin(&mut self, extend: bool) { + debug!("Infinit playlist reaches end, recalculate clip begins."); + + let mut time_sec = time_in_seconds(); + + if extend { + time_sec = self.start_sec + self.json_playlist.length.unwrap(); + } + + self.json_playlist.start_sec = Some(time_sec); + set_defaults(&mut self.json_playlist); + *self.player_control.current_list.lock().unwrap() = self.json_playlist.program.clone(); + } } /// Build the playlist iterator @@ -334,7 +352,7 @@ impl Iterator for CurrentProgram { type Item = Media; fn next(&mut self) -> Option { - self.last_json_path = self.json_path.clone(); + self.last_json_path = self.json_playlist.path.clone(); self.last_node_ad = self.current_node.last_ad; self.check_for_playlist(self.playout_stat.list_init.load(Ordering::SeqCst)); @@ -342,7 +360,7 @@ impl Iterator for CurrentProgram { trace!("Init playlist, from next iterator"); let mut init_clip_is_filler = false; - if self.json_path.is_some() { + if self.json_playlist.path.is_some() { init_clip_is_filler = self.init_clip(); } @@ -420,7 +438,7 @@ impl Iterator for CurrentProgram { let (_, total_delta) = get_delta(&self.config, &self.start_sec); if !self.config.playlist.infinit - && self.last_json_path == self.json_path + && self.last_json_path == self.json_playlist.path && total_delta.abs() > 1.0 { // Playlist is to early finish, @@ -438,6 +456,10 @@ impl Iterator for CurrentProgram { drop(c_list); + if self.config.playlist.infinit { + self.recalculate_begin(false) + } + self.player_control.current_index.store(0, Ordering::SeqCst); self.current_node = gen_source( &self.config, @@ -502,6 +524,7 @@ fn timed_source( if (total_delta > node.out - node.seek && !last) || node.index.unwrap() < 2 || !config.playlist.length.contains(':') + || config.playlist.infinit { // when we are in the 24 hour range, get the clip new_node.process = Some(true); @@ -742,7 +765,7 @@ fn handle_list_init( debug!("Playlist init"); let (_, total_delta) = get_delta(config, &node.begin.unwrap()); - if node.out - node.seek > total_delta { + if !config.playlist.infinit && node.out - node.seek > total_delta { node.out = total_delta + node.seek; } diff --git a/ffplayout-engine/src/main.rs b/ffplayout-engine/src/main.rs index d4cbed92..547a9b74 100644 --- a/ffplayout-engine/src/main.rs +++ b/ffplayout-engine/src/main.rs @@ -103,9 +103,12 @@ fn main() -> Result<(), ProcError> { let messages = Arc::new(Mutex::new(Vec::new())); // try to create logging folder, if not exist - if config.logging.log_to_file && config.logging.path.is_dir() { + if config.logging.log_to_file + && !config.logging.path.is_dir() + && !config.logging.path.ends_with(".log") + { if let Err(e) = fs::create_dir_all(&config.logging.path) { - println!("Logging path not exists! {e}"); + eprintln!("Logging path not exists! {e}"); exit(1); } diff --git a/ffplayout-engine/src/output/desktop.rs b/ffplayout-engine/src/output/desktop.rs index ea739057..2b46fd02 100644 --- a/ffplayout-engine/src/output/desktop.rs +++ b/ffplayout-engine/src/output/desktop.rs @@ -2,7 +2,7 @@ use std::process::{self, Command, Stdio}; use simplelog::*; -use ffplayout_lib::{filter::v_drawtext, utils::PlayoutConfig, vec_strings}; +use ffplayout_lib::{filter::v_drawtext, utils::PlayoutConfig, vec_strings, ADVANCED_CONFIG}; /// Desktop Output /// @@ -10,16 +10,18 @@ use ffplayout_lib::{filter::v_drawtext, utils::PlayoutConfig, vec_strings}; pub fn output(config: &PlayoutConfig, log_format: &str) -> process::Child { let mut enc_filter: Vec = vec![]; - let mut enc_cmd = vec_strings![ - "-hide_banner", - "-nostats", - "-v", - log_format, + let mut enc_cmd = vec_strings!["-hide_banner", "-nostats", "-v", log_format]; + + if let Some(encoder_input_cmd) = &ADVANCED_CONFIG.encoder.input_cmd { + enc_cmd.append(&mut encoder_input_cmd.clone()); + } + + enc_cmd.append(&mut vec_strings![ "-i", "pipe:0", "-window_title", "ffplayout" - ]; + ]); if let Some(mut cmd) = config.out.output_cmd.clone() { if !cmd.iter().any(|i| { diff --git a/ffplayout-engine/src/output/hls.rs b/ffplayout-engine/src/output/hls.rs index 6c2042ee..ccf9464c 100644 --- a/ffplayout-engine/src/output/hls.rs +++ b/ffplayout-engine/src/output/hls.rs @@ -34,7 +34,7 @@ use ffplayout_lib::{ controller::ProcessUnit::*, get_delta, sec_to_time, stderr_reader, test_tcp_port, Media, PlayerControl, PlayoutConfig, PlayoutStatus, ProcessControl, }, - vec_strings, + vec_strings, ADVANCED_CONFIG, }; /// Ingest Server for HLS @@ -47,10 +47,15 @@ fn ingest_to_hls_server( let mut server_prefix = vec_strings!["-hide_banner", "-nostats", "-v", "level+info"]; let stream_input = config.ingest.input_cmd.clone().unwrap(); - server_prefix.append(&mut stream_input.clone()); let mut dummy_media = Media::new(0, "Live Stream", false); dummy_media.unit = Ingest; + if let Some(ingest_input_cmd) = &ADVANCED_CONFIG.ingest.input_cmd { + server_prefix.append(&mut ingest_input_cmd.clone()); + } + + server_prefix.append(&mut stream_input.clone()); + let mut is_running; if let Some(url) = stream_input.iter().find(|s| s.contains("://")) { @@ -197,6 +202,10 @@ pub fn write_hls( let mut enc_prefix = vec_strings!["-hide_banner", "-nostats", "-v", &ff_log_format]; + if let Some(encoder_input_cmd) = &ADVANCED_CONFIG.encoder.input_cmd { + enc_prefix.append(&mut encoder_input_cmd.clone()); + } + let mut read_rate = 1.0; if let Some(begin) = &node.begin { diff --git a/ffplayout-engine/src/output/mod.rs b/ffplayout-engine/src/output/mod.rs index 76c9b5d3..6fe25df3 100644 --- a/ffplayout-engine/src/output/mod.rs +++ b/ffplayout-engine/src/output/mod.rs @@ -19,11 +19,14 @@ pub use hls::write_hls; use crate::input::{ingest_server, source_generator}; use crate::utils::task_runner; -use ffplayout_lib::utils::{ - sec_to_time, stderr_reader, OutputMode::*, PlayerControl, PlayoutConfig, PlayoutStatus, - ProcessControl, ProcessUnit::*, -}; use ffplayout_lib::vec_strings; +use ffplayout_lib::{ + utils::{ + sec_to_time, stderr_reader, OutputMode::*, PlayerControl, PlayoutConfig, PlayoutStatus, + ProcessControl, ProcessUnit::*, + }, + ADVANCED_CONFIG, +}; /// Player /// @@ -104,8 +107,18 @@ pub fn player( continue; } + let c_index = if cfg!(debug_assertions) { + format!( + " ({}/{})", + node.index.unwrap() + 1, + play_control.current_list.lock().unwrap().len() + ) + } else { + String::new() + }; + info!( - "Play for {}: {} {}", + "Play for {}{c_index}: {} {}", sec_to_time(node.out - node.seek), node.source, node.audio @@ -130,6 +143,11 @@ pub fn player( } let mut dec_cmd = vec_strings!["-hide_banner", "-nostats", "-v", &ff_log_format]; + + if let Some(decoder_input_cmd) = &ADVANCED_CONFIG.decoder.input_cmd { + dec_cmd.append(&mut decoder_input_cmd.clone()); + } + dec_cmd.append(&mut cmd); if let Some(mut filter) = node.filter { diff --git a/ffplayout-engine/src/utils/mod.rs b/ffplayout-engine/src/utils/mod.rs index 9df2910e..dfed8bfc 100644 --- a/ffplayout-engine/src/utils/mod.rs +++ b/ffplayout-engine/src/utils/mod.rs @@ -65,7 +65,7 @@ pub fn get_config(args: Args) -> Result { } if let Some(log_path) = args.log { - if log_path != Path::new("none") && log_path.is_dir() { + if log_path != Path::new("none") { config.logging.log_to_file = true; config.logging.path = log_path; } else { diff --git a/ffplayout-frontend b/ffplayout-frontend index 737d86f9..3802e75c 160000 --- a/ffplayout-frontend +++ b/ffplayout-frontend @@ -1 +1 @@ -Subproject commit 737d86f901a9275b13e164378ad1c231c6370c1f +Subproject commit 3802e75c461eeea0febf20c1ea2c97cb89dd8d41 diff --git a/lib/Cargo.toml b/lib/Cargo.toml index a02aa7ae..de893519 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -14,13 +14,14 @@ crossbeam-channel = "0.5" derive_more = "0.99" ffprobe = "0.3" file-rotate = "0.7" +lazy_static = "1.4" lettre = { version = "0.11", features = ["builder", "rustls-tls", "smtp-transport"], default-features = false } lexical-sort = "0.3" log = "0.4" num-traits = "0.2" rand = "0.8" regex = "1" -reqwest = { version = "0.11", default-features = false, features = ["blocking", "json", "rustls-tls"] } +reqwest = { version = "0.12", default-features = false, features = ["blocking", "json", "rustls-tls"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde_yaml = "0.9" diff --git a/lib/src/filter/mod.rs b/lib/src/filter/mod.rs index dffc054d..289026d9 100644 --- a/lib/src/filter/mod.rs +++ b/lib/src/filter/mod.rs @@ -11,8 +11,10 @@ mod custom; pub mod v_drawtext; use crate::utils::{ - controller::ProcessUnit::*, fps_calc, is_close, Media, OutputMode::*, PlayoutConfig, + controller::ProcessUnit::*, custom_format, fps_calc, is_close, Media, OutputMode::*, + PlayoutConfig, }; +use crate::ADVANCED_CONFIG; use super::vec_strings; @@ -184,7 +186,12 @@ impl Default for Filters { fn deinterlace(field_order: &Option, chain: &mut Filters) { if let Some(order) = field_order { if order != "progressive" { - chain.add_filter("yadif=0:-1:0", 0, Video) + let deinterlace = match &ADVANCED_CONFIG.decoder.filters.deinterlace { + Some(deinterlace) => deinterlace.clone(), + None => "yadif=0:-1:0".to_string(), + }; + + chain.add_filter(&deinterlace, 0, Video); } } } @@ -195,25 +202,45 @@ fn pad(aspect: f64, chain: &mut Filters, v_stream: &ffprobe::Stream, config: &Pl if let (Some(w), Some(h)) = (v_stream.width, v_stream.height) { if w > config.processing.width && aspect > config.processing.aspect { - scale = format!("scale={}:-1,", config.processing.width); + scale = match &ADVANCED_CONFIG.decoder.filters.pad_scale_w { + Some(pad_scale_w) => custom_format(pad_scale_w, &[&config.processing.width]), + None => format!("scale={}:-1,", config.processing.width), + }; } else if h > config.processing.height && aspect < config.processing.aspect { - scale = format!("scale=-1:{},", config.processing.height); + scale = match &ADVANCED_CONFIG.decoder.filters.pad_scale_h { + Some(pad_scale_h) => custom_format(pad_scale_h, &[&config.processing.width]), + None => format!("scale=-1:{},", config.processing.height), + }; } } - chain.add_filter( - &format!( - "{scale}pad=max(iw\\,ih*({0}/{1})):ow/({0}/{1}):(ow-iw)/2:(oh-ih)/2", - config.processing.width, config.processing.height + + let pad = match &ADVANCED_CONFIG.decoder.filters.pad_video { + Some(pad_video) => custom_format( + pad_video, + &[ + &scale, + &config.processing.width.to_string(), + &config.processing.height.to_string(), + ], ), - 0, - Video, - ) + None => format!( + "{}pad=max(iw\\,ih*({1}/{2})):ow/({1}/{2}):(ow-iw)/2:(oh-ih)/2", + scale, config.processing.width, config.processing.height + ), + }; + + chain.add_filter(&pad, 0, Video) } } fn fps(fps: f64, chain: &mut Filters, config: &PlayoutConfig) { if fps != config.processing.fps { - chain.add_filter(&format!("fps={}", config.processing.fps), 0, Video) + let fps_filter = match &ADVANCED_CONFIG.decoder.filters.fps { + Some(fps) => custom_format(fps, &[&config.processing.fps]), + None => format!("fps={}", config.processing.fps), + }; + + chain.add_filter(&fps_filter, 0, Video) } } @@ -227,39 +254,49 @@ fn scale( // width: i64, height: i64 if let (Some(w), Some(h)) = (width, height) { if w != config.processing.width || h != config.processing.height { - chain.add_filter( - &format!( + let scale = match &ADVANCED_CONFIG.decoder.filters.scale { + Some(scale) => custom_format( + scale, + &[&config.processing.width, &config.processing.height], + ), + None => format!( "scale={}:{}", config.processing.width, config.processing.height ), - 0, - Video, - ); + }; + + chain.add_filter(&scale, 0, Video); } else { chain.add_filter("null", 0, Video); } if !is_close(aspect, config.processing.aspect, 0.03) { - chain.add_filter( - &format!("setdar=dar={}", config.processing.aspect), - 0, - Video, - ) + let dar = match &ADVANCED_CONFIG.decoder.filters.set_dar { + Some(set_dar) => custom_format(set_dar, &[&config.processing.aspect]), + None => format!("setdar=dar={}", config.processing.aspect), + }; + + chain.add_filter(&dar, 0, Video); } } else { - chain.add_filter( - &format!( + let scale = match &ADVANCED_CONFIG.decoder.filters.scale { + Some(scale) => custom_format( + scale, + &[&config.processing.width, &config.processing.height], + ), + None => format!( "scale={}:{}", config.processing.width, config.processing.height ), - 0, - Video, - ); - chain.add_filter( - &format!("setdar=dar={}", config.processing.aspect), - 0, - Video, - ) + }; + chain.add_filter(&scale, 0, Video); + + let dar = match &ADVANCED_CONFIG.decoder.filters.set_dar { + Some(set_dar) => custom_format(set_dar, &[&config.processing.aspect]), + None => format!("setdar=dar={}", config.processing.aspect), + }; + + chain.add_filter(&dar, 0, Video); } } @@ -276,15 +313,21 @@ fn fade(node: &mut Media, chain: &mut Filters, nr: i32, filter_type: FilterType) } if node.seek > 0.0 || node.unit == Ingest { - chain.add_filter(&format!("{t}fade=in:st=0:d=0.5"), nr, filter_type) + let fade_in = match &ADVANCED_CONFIG.decoder.filters.fade_in { + Some(fade) => custom_format(fade, &[t]), + None => format!("{t}fade=in:st=0:d=0.5"), + }; + + chain.add_filter(&fade_in, nr, filter_type); } if (node.out != node.duration && node.out - node.seek > 1.0) || fade_audio { - chain.add_filter( - &format!("{t}fade=out:st={}:d=1.0", (node.out - node.seek - 1.0)), - nr, - filter_type, - ) + let fade_out = match &ADVANCED_CONFIG.decoder.filters.fade_out { + Some(fade) => custom_format(fade, &[t, &(node.out - node.seek - 1.0).to_string()]), + None => format!("{t}fade=out:st={}:d=1.0", (node.out - node.seek - 1.0)), + }; + + chain.add_filter(&fade_out, nr, filter_type); } } @@ -296,23 +339,39 @@ fn overlay(node: &mut Media, chain: &mut Filters, config: &PlayoutConfig) { let mut scale = String::new(); if !config.processing.logo_scale.is_empty() { - scale = format!(",scale={}", config.processing.logo_scale); + scale = match &ADVANCED_CONFIG.decoder.filters.overlay_logo_scale { + Some(logo_scale) => custom_format(logo_scale, &[&config.processing.logo_scale]), + None => format!(",scale={}", config.processing.logo_scale), + } } - let mut logo_chain = format!( - "null[v];movie={}:loop=0,setpts=N/(FRAME_RATE*TB),format=rgba,colorchannelmixer=aa={}{scale}[l];[v][l]{}:shortest=1", - config.processing.logo.replace('\\', "/").replace(':', "\\\\:"), config.processing.logo_opacity, config.processing.logo_filter - ); + let mut logo_chain = match &ADVANCED_CONFIG.decoder.filters.overlay_logo { + Some(overlay) => custom_format(overlay, &[ + &config.processing.logo.replace('\\', "/").replace(':', "\\\\:"), + &config.processing.logo_opacity.to_string(), + &scale.to_string(), + &config.processing.logo_filter, + ]), + None => format!( + "null[v];movie={}:loop=0,setpts=N/(FRAME_RATE*TB),format=rgba,colorchannelmixer=aa={}{scale}[l];[v][l]{}:shortest=1", + config.processing.logo.replace('\\', "/").replace(':', "\\\\:"), config.processing.logo_opacity, config.processing.logo_filter + ) + }; if node.last_ad { - logo_chain.push_str(",fade=in:st=0:d=1.0:alpha=1") + match &ADVANCED_CONFIG.decoder.filters.overlay_logo_fade_in { + Some(fade_in) => logo_chain.push_str(fade_in), + None => logo_chain.push_str(",fade=in:st=0:d=1.0:alpha=1"), + } } if node.next_ad { - logo_chain.push_str(&format!( - ",fade=out:st={}:d=1.0:alpha=1", - node.out - node.seek - 1.0 - )) + let length = node.out - node.seek - 1.0; + + match &ADVANCED_CONFIG.decoder.filters.overlay_logo_fade_out { + Some(fade_out) => logo_chain.push_str(&custom_format(fade_out, &[length])), + None => logo_chain.push_str(&format!(",fade=out:st={length}:d=1.0:alpha=1")), + } } chain.add_filter(&logo_chain, 0, Video); @@ -328,14 +387,14 @@ fn extend_video(node: &mut Media, chain: &mut Filters) { .and_then(|v| v.parse::().ok()) { if node.out - node.seek > video_duration - node.seek + 0.1 && node.duration >= node.out { - chain.add_filter( - &format!( - "tpad=stop_mode=add:stop_duration={}", - (node.out - node.seek) - (video_duration - node.seek) - ), - 0, - Video, - ) + let duration = (node.out - node.seek) - (video_duration - node.seek); + + let tpad = match &ADVANCED_CONFIG.decoder.filters.tpad { + Some(pad) => custom_format(pad, &[duration]), + None => format!("tpad=stop_mode=add:stop_duration={duration}"), + }; + + chain.add_filter(&tpad, 0, Video) } } } @@ -357,10 +416,14 @@ fn add_text( } fn add_audio(node: &Media, chain: &mut Filters, nr: i32) { - let audio = format!( - "aevalsrc=0:channel_layout=stereo:duration={}:sample_rate=48000", - node.out - node.seek - ); + let audio = match &ADVANCED_CONFIG.decoder.filters.aevalsrc { + Some(aevalsrc) => custom_format(aevalsrc, &[node.out - node.seek]), + None => format!( + "aevalsrc=0:channel_layout=stereo:duration={}:sample_rate=48000", + node.out - node.seek + ), + }; + chain.add_filter(&audio, nr, Audio); } @@ -375,11 +438,12 @@ fn extend_audio(node: &mut Media, chain: &mut Filters, nr: i32) { { if node.out - node.seek > audio_duration - node.seek + 0.1 && node.duration >= node.out { - chain.add_filter( - &format!("apad=whole_dur={}", node.out - node.seek), - nr, - Audio, - ) + let apad = match &ADVANCED_CONFIG.decoder.filters.apad { + Some(apad) => custom_format(apad, &[node.out - node.seek]), + None => format!("apad=whole_dur={}", node.out - node.seek), + }; + + chain.add_filter(&apad, nr, Audio) } } } @@ -387,7 +451,12 @@ fn extend_audio(node: &mut Media, chain: &mut Filters, nr: i32) { fn audio_volume(chain: &mut Filters, config: &PlayoutConfig, nr: i32) { if config.processing.volume != 1.0 { - chain.add_filter(&format!("volume={}", config.processing.volume), nr, Audio) + let volume = match &ADVANCED_CONFIG.decoder.filters.volume { + Some(volume) => custom_format(volume, &[config.processing.volume]), + None => format!("volume={}", config.processing.volume), + }; + + chain.add_filter(&volume, nr, Audio) } } @@ -418,8 +487,12 @@ pub fn split_filter(chain: &mut Filters, count: usize, nr: i32, filter_type: Fil } } - let split_filter = format!("split={count}{}", out_link.join("")); - chain.add_filter(&split_filter, nr, filter_type); + let split = match &ADVANCED_CONFIG.decoder.filters.split { + Some(split) => custom_format(split, &[count.to_string(), out_link.join("")]), + None => format!("split={count}{}", out_link.join("")), + }; + + chain.add_filter(&split, nr, filter_type); } } diff --git a/lib/src/filter/v_drawtext.rs b/lib/src/filter/v_drawtext.rs index 9944aa54..1b655de8 100644 --- a/lib/src/filter/v_drawtext.rs +++ b/lib/src/filter/v_drawtext.rs @@ -6,7 +6,8 @@ use std::{ use regex::Regex; -use crate::utils::{controller::ProcessUnit::*, Media, PlayoutConfig}; +use crate::utils::{controller::ProcessUnit::*, custom_format, Media, PlayoutConfig}; +use crate::ADVANCED_CONFIG; pub fn filter_node( config: &PlayoutConfig, @@ -43,7 +44,11 @@ pub fn filter_node( .replace('\'', "'\\\\\\''") .replace('%', "\\\\\\%") .replace(':', "\\:"); - filter = format!("drawtext=text='{escaped_text}':{}{font}", config.text.style) + + filter = match &ADVANCED_CONFIG.decoder.filters.drawtext_from_file { + Some(drawtext) => custom_format(drawtext, &[&escaped_text, &config.text.style, &font]), + None => format!("drawtext=text='{escaped_text}':{}{font}", config.text.style), + }; } else if let Some(socket) = zmq_socket { let mut filter_cmd = format!("text=''{font}"); @@ -53,10 +58,13 @@ pub fn filter_node( } } - filter = format!( - "zmq=b=tcp\\\\://'{}',drawtext@dyntext={filter_cmd}", - socket.replace(':', "\\:") - ) + filter = match &ADVANCED_CONFIG.decoder.filters.drawtext_from_zmq { + Some(drawtext) => custom_format(drawtext, &[&socket.replace(':', "\\:"), &filter_cmd]), + None => format!( + "zmq=b=tcp\\\\://'{}',drawtext@dyntext={filter_cmd}", + socket.replace(':', "\\:") + ), + }; } filter diff --git a/lib/src/lib.rs b/lib/src/lib.rs index f01731e7..a3b6350f 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -1,6 +1,16 @@ +use std::sync::Arc; + extern crate log; extern crate simplelog; +use lazy_static::lazy_static; + pub mod filter; pub mod macros; pub mod utils; + +use utils::advanced_config::AdvancedConfig; + +lazy_static! { + pub static ref ADVANCED_CONFIG: Arc = Arc::new(AdvancedConfig::new()); +} diff --git a/lib/src/utils/advanced_config.rs b/lib/src/utils/advanced_config.rs new file mode 100644 index 00000000..1f5a6d01 --- /dev/null +++ b/lib/src/utils/advanced_config.rs @@ -0,0 +1,102 @@ +use std::{ + env, + fs::File, + path::{Path, PathBuf}, +}; + +use serde::{Deserialize, Serialize}; +use shlex::split; + +#[derive(Debug, Default, Serialize, Deserialize, Clone)] +pub struct AdvancedConfig { + pub help: Option, + pub decoder: DecoderConfig, + pub encoder: EncoderConfig, + pub ingest: IngestConfig, +} + +#[derive(Debug, Default, Serialize, Deserialize, Clone)] +pub struct DecoderConfig { + pub input_param: Option, + pub output_param: Option, + pub filters: Filters, + #[serde(skip_serializing, skip_deserializing)] + pub input_cmd: Option>, + #[serde(skip_serializing, skip_deserializing)] + pub output_cmd: Option>, +} + +#[derive(Debug, Default, Serialize, Deserialize, Clone)] +pub struct EncoderConfig { + pub input_param: Option, + #[serde(skip_serializing, skip_deserializing)] + pub input_cmd: Option>, +} + +#[derive(Debug, Default, Serialize, Deserialize, Clone)] +pub struct IngestConfig { + pub input_param: Option, + #[serde(skip_serializing, skip_deserializing)] + pub input_cmd: Option>, +} + +#[derive(Debug, Default, Serialize, Deserialize, Clone)] +pub struct Filters { + pub deinterlace: Option, + pub pad_scale_w: Option, + pub pad_scale_h: Option, + pub pad_video: Option, + pub fps: Option, + pub scale: Option, + pub set_dar: Option, + pub fade_in: Option, + pub fade_out: Option, + pub overlay_logo_scale: Option, + pub overlay_logo: Option, + pub overlay_logo_fade_in: Option, + pub overlay_logo_fade_out: Option, + pub tpad: Option, + pub drawtext_from_file: Option, + pub drawtext_from_zmq: Option, + pub aevalsrc: Option, + pub apad: Option, + pub volume: Option, + pub split: Option, +} + +impl AdvancedConfig { + pub fn new() -> Self { + let mut config: AdvancedConfig = Default::default(); + let mut config_path = PathBuf::from("/etc/ffplayout/advanced.yml"); + + if !config_path.is_file() { + if Path::new("./assets/advanced.yml").is_file() { + config_path = PathBuf::from("./assets/advanced.yml") + } else if let Some(p) = env::current_exe().ok().as_ref().and_then(|op| op.parent()) { + config_path = p.join("advanced.yml") + }; + } + + if let Ok(f) = File::open(&config_path) { + config = serde_yaml::from_reader(f).expect("Could not read advanced config file"); + + if let Some(input_parm) = &config.decoder.input_param { + config.decoder.input_cmd = split(input_parm); + } + + if let Some(output_param) = &config.decoder.output_param { + config.decoder.output_cmd = split(output_param); + } + + if let Some(input_param) = &config.encoder.input_param { + config.encoder.input_cmd = split(input_param); + } + + if let Some(input_param) = &config.ingest.input_param { + config.ingest.input_cmd = split(input_param); + } + }; + + config + } +} diff --git a/lib/src/utils/config.rs b/lib/src/utils/config.rs index 3fa053e0..7eb0aa92 100644 --- a/lib/src/utils/config.rs +++ b/lib/src/utils/config.rs @@ -11,6 +11,8 @@ use log::LevelFilter; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use shlex::split; +use crate::ADVANCED_CONFIG; + use super::vec_strings; use crate::utils::{free_tcp_socket, home_dir, time_to_sec, OutputMode::*}; @@ -375,7 +377,7 @@ impl PlayoutConfig { let f = match File::open(&config_path) { Ok(file) => file, Err(_) => { - println!( + eprintln!( "{config_path:?} doesn't exists!\nPut \"ffplayout.yml\" in \"/etc/playout/\" or beside the executable!" ); process::exit(1); @@ -424,23 +426,29 @@ impl PlayoutConfig { config.processing.audio_tracks = 1 } - let bitrate = format!( - "{}k", - config.processing.width * config.processing.height / 16 - ); - - let buff_size = format!( - "{}k", - (config.processing.width * config.processing.height / 16) / 2 - ); - let mut process_cmd = vec_strings![]; if config.processing.audio_only { process_cmd.append(&mut vec_strings!["-vn"]); } else if config.processing.copy_video { process_cmd.append(&mut vec_strings!["-c:v", "copy"]); + } else if let Some(decoder_cmd) = &ADVANCED_CONFIG.decoder.output_cmd { + if !decoder_cmd.contains(&"-r".to_string()) { + process_cmd.append(&mut vec_strings!["-r", &config.processing.fps]); + } + + process_cmd.append(&mut decoder_cmd.clone()); } else { + let bitrate = format!( + "{}k", + config.processing.width * config.processing.height / 16 + ); + + let buff_size = format!( + "{}k", + (config.processing.width * config.processing.height / 16) / 2 + ); + process_cmd.append(&mut vec_strings![ "-pix_fmt", "yuv420p", @@ -463,7 +471,7 @@ impl PlayoutConfig { if config.processing.copy_audio { process_cmd.append(&mut vec_strings!["-c:a", "copy"]); - } else { + } else if ADVANCED_CONFIG.decoder.output_cmd.is_none() { process_cmd.append(&mut pre_audio_codec( &config.processing.custom_filter, &config.ingest.custom_filter, diff --git a/lib/src/utils/generator.rs b/lib/src/utils/generator.rs index a0b8449e..7beb60c5 100644 --- a/lib/src/utils/generator.rs +++ b/lib/src/utils/generator.rs @@ -272,8 +272,9 @@ pub fn generate_playlist( let mut playlist = JsonPlaylist { channel: channel.clone(), date, - current_file: None, + path: None, start_sec: None, + length: None, modified: None, program: vec![], }; diff --git a/lib/src/utils/import.rs b/lib/src/utils/import.rs index ce2c6ce5..a266ba99 100644 --- a/lib/src/utils/import.rs +++ b/lib/src/utils/import.rs @@ -19,8 +19,9 @@ pub fn import_file( let mut playlist = JsonPlaylist { channel: channel_name.unwrap_or_else(|| "Channel 1".to_string()), date: date.to_string(), - current_file: None, + path: None, start_sec: None, + length: None, modified: None, program: vec![], }; diff --git a/lib/src/utils/json_serializer.rs b/lib/src/utils/json_serializer.rs index 920e523a..a486a7d3 100644 --- a/lib/src/utils/json_serializer.rs +++ b/lib/src/utils/json_serializer.rs @@ -9,8 +9,8 @@ use std::{ use simplelog::*; use crate::utils::{ - controller::ProcessUnit::*, get_date, is_remote, modified_time, time_from_header, - validate_playlist, Media, PlayerControl, PlayoutConfig, DUMMY_LEN, + get_date, is_remote, modified_time, time_from_header, validate_playlist, Media, PlayerControl, + PlayoutConfig, DUMMY_LEN, }; /// This is our main playlist object, it holds all necessary information for the current day. @@ -24,7 +24,10 @@ pub struct JsonPlaylist { pub start_sec: Option, #[serde(skip_serializing, skip_deserializing)] - pub current_file: Option, + pub length: Option, + + #[serde(skip_serializing, skip_deserializing)] + pub path: Option, #[serde(skip_serializing, skip_deserializing)] pub modified: Option, @@ -33,7 +36,7 @@ pub struct JsonPlaylist { } impl JsonPlaylist { - fn new(date: String, start: f64) -> Self { + pub fn new(date: String, start: f64) -> Self { let mut media = Media::new(0, "", false); media.begin = Some(start); media.duration = DUMMY_LEN; @@ -42,7 +45,8 @@ impl JsonPlaylist { channel: "Channel 1".into(), date, start_sec: Some(start), - current_file: None, + length: Some(86400.0), + path: None, modified: None, program: vec![media], } @@ -61,13 +65,9 @@ fn default_channel() -> String { "Channel 1".to_string() } -fn set_defaults( - mut playlist: JsonPlaylist, - current_file: String, - mut start_sec: f64, -) -> JsonPlaylist { - playlist.current_file = Some(current_file); - playlist.start_sec = Some(start_sec); +pub fn set_defaults(playlist: &mut JsonPlaylist) { + let mut start_sec = playlist.start_sec.unwrap(); + let mut length = 0.0; // Add extra values to every media clip for (i, item) in playlist.program.iter_mut().enumerate() { @@ -78,69 +78,18 @@ fn set_defaults( item.process = Some(true); item.filter = None; - start_sec += item.out - item.seek; + let dur = item.out - item.seek; + start_sec += dur; + length += dur; } - playlist -} - -fn loop_playlist( - config: &PlayoutConfig, - current_file: String, - mut playlist: JsonPlaylist, -) -> JsonPlaylist { - let start_sec = config.playlist.start_sec.unwrap(); - let mut begin = start_sec; - let length = config.playlist.length_sec.unwrap(); - let mut program_list = vec![]; - let mut index = 0; - - playlist.current_file = Some(current_file); - playlist.start_sec = Some(start_sec); - - 'program_looper: loop { - for item in playlist.program.iter() { - let media = Media { - index: Some(index), - begin: Some(begin), - seek: item.seek, - out: item.out, - duration: item.duration, - duration_audio: item.duration_audio, - category: item.category.clone(), - source: item.source.clone(), - audio: item.audio.clone(), - cmd: item.cmd.clone(), - probe: item.probe.clone(), - probe_audio: item.probe_audio.clone(), - process: Some(true), - unit: Decoder, - last_ad: false, - next_ad: false, - filter: None, - custom_filter: String::new(), - }; - - if begin < start_sec + length { - program_list.push(media); - } else { - break 'program_looper; - } - - begin += item.out - item.seek; - index += 1; - } - } - - playlist.program = program_list; - - playlist + playlist.length = Some(length) } /// Read json playlist file, fills JsonPlaylist struct and set some extra values, /// which we need to process. pub fn read_json( - config: &PlayoutConfig, + config: &mut PlayoutConfig, player_control: &PlayerControl, path: Option, is_terminated: Arc, @@ -179,6 +128,8 @@ pub fn read_json( if let Ok(body) = resp.text() { let mut playlist: JsonPlaylist = serde_json::from_str(&body).expect("Could't read remote json playlist."); + playlist.path = Some(current_file); + playlist.start_sec = Some(start_sec); if let Some(time) = time_from_header(&headers) { playlist.modified = Some(time.to_string()); @@ -197,10 +148,9 @@ pub fn read_json( }); } - match config.playlist.infinit { - true => return loop_playlist(config, current_file, playlist), - false => return set_defaults(playlist, current_file, start_sec), - } + set_defaults(&mut playlist); + + return playlist; } } } @@ -225,6 +175,8 @@ pub fn read_json( playlist = JsonPlaylist::new(date, start_sec) } + playlist.path = Some(current_file); + playlist.start_sec = Some(start_sec); playlist.modified = modified; let list_clone = playlist.clone(); @@ -235,10 +187,9 @@ pub fn read_json( }); } - match config.playlist.infinit { - true => return loop_playlist(config, current_file, playlist), - false => return set_defaults(playlist, current_file, start_sec), - } + set_defaults(&mut playlist); + + return playlist; } error!("Playlist {current_file} not exist!"); diff --git a/lib/src/utils/json_validate.rs b/lib/src/utils/json_validate.rs index 38c38913..627148bb 100644 --- a/lib/src/utils/json_validate.rs +++ b/lib/src/utils/json_validate.rs @@ -236,5 +236,16 @@ pub fn validate_playlist( ); } - debug!("Validation done, in {:.3?} ...", timer.elapsed(),); + if config.general.validate { + info!( + "[Validation] Playlist length: {}", + sec_to_time(begin - config.playlist.start_sec.unwrap()) + ); + } + + debug!( + "Validation done, in {:.3?}, playlist length: {} ...", + timer.elapsed(), + sec_to_time(begin - config.playlist.start_sec.unwrap()) + ); } diff --git a/lib/src/utils/logging.rs b/lib/src/utils/logging.rs index 789c5aef..ffef82e0 100644 --- a/lib/src/utils/logging.rs +++ b/lib/src/utils/logging.rs @@ -218,7 +218,7 @@ pub fn init_logging( } else if app_config.path.is_file() { log_path = app_config.path } else { - println!("Logging path not exists!") + eprintln!("Logging path not exists!") } let log_file = FileRotate::new( diff --git a/lib/src/utils/mod.rs b/lib/src/utils/mod.rs index e78172e1..e8012be7 100644 --- a/lib/src/utils/mod.rs +++ b/lib/src/utils/mod.rs @@ -1,18 +1,18 @@ use std::{ ffi::OsStr, + fmt, fs::{self, metadata, File}, io::{BufRead, BufReader, Error}, net::TcpListener, path::{Path, PathBuf}, process::{exit, ChildStderr, Command, Stdio}, sync::{Arc, Mutex}, - time::{self, UNIX_EPOCH}, }; #[cfg(not(windows))] use std::env; -use chrono::{prelude::*, Duration}; +use chrono::{prelude::*, TimeDelta}; use ffprobe::{ffprobe, Stream as FFStream}; use rand::prelude::*; use regex::Regex; @@ -21,6 +21,7 @@ use serde::{de::Deserializer, Deserialize, Serialize}; use serde_json::json; use simplelog::*; +pub mod advanced_config; pub mod config; pub mod controller; pub mod errors; @@ -359,11 +360,15 @@ pub fn get_date(seek: bool, start: f64, get_next: bool) -> String { let local: DateTime = time_now(); if seek && start > time_in_seconds() { - return (local - Duration::days(1)).format("%Y-%m-%d").to_string(); + return (local - TimeDelta::try_days(1).unwrap()) + .format("%Y-%m-%d") + .to_string(); } if start == 0.0 && get_next && time_in_seconds() > 86397.9 { - return (local + Duration::days(1)).format("%Y-%m-%d").to_string(); + return (local + TimeDelta::try_days(1).unwrap()) + .format("%Y-%m-%d") + .to_string(); } local.format("%Y-%m-%d").to_string() @@ -421,11 +426,12 @@ pub fn time_to_sec(time_str: &str) -> f64 { /// Convert floating number (seconds) to a formatted time string. pub fn sec_to_time(sec: f64) -> String { - let d = UNIX_EPOCH + time::Duration::from_millis((sec * 1000.0) as u64); - // Create DateTime from SystemTime - let date_time = DateTime::::from(d); - - date_time.format("%H:%M:%S%.3f").to_string() + format!( + "{:0>2}:{:0>2}:{:06.3}", + (sec / 60.0 / 60.0) as i32, + (sec / 60.0 % 60.0) as i32, + (sec % 60.0), + ) } /// get file extension @@ -457,22 +463,27 @@ pub fn sum_durations(clip_list: &Vec) -> f64 { pub fn get_delta(config: &PlayoutConfig, begin: &f64) -> (f64, f64) { let mut current_time = time_in_seconds(); let start = config.playlist.start_sec.unwrap(); - let length = time_to_sec(&config.playlist.length); + let length = config.playlist.length_sec.unwrap_or(86400.0); let mut target_length = 86400.0; if length > 0.0 && length != target_length { target_length = length } + if begin == &start && start == 0.0 && 86400.0 - current_time < 4.0 { - current_time -= target_length + current_time -= 86400.0 } else if start >= current_time && begin != &start { - current_time += target_length + current_time += 86400.0 } let mut current_delta = begin - current_time; - if is_close(current_delta, 86400.0, config.general.stop_threshold) { - current_delta -= 86400.0 + if is_close( + current_delta.abs(), + 86400.0, + config.general.stop_threshold + 2.0, + ) { + current_delta = current_delta.abs() - 86400.0 } let total_delta = if current_time < start { @@ -910,7 +921,11 @@ pub fn get_date_range(date_range: &[String]) -> Vec { let days = duration.num_days() + 1; for day in 0..days { - range.push((start + Duration::days(day)).format("%Y-%m-%d").to_string()); + range.push( + (start + TimeDelta::try_days(day).unwrap()) + .format("%Y-%m-%d") + .to_string(), + ); } range @@ -928,6 +943,46 @@ pub fn parse_log_level_filter(s: &str) -> Result { } } +pub fn custom_format(template: &str, args: &[T]) -> String { + let mut filled_template = String::new(); + let mut arg_iter = args.iter().map(|x| format!("{}", x)); + let mut template_iter = template.chars(); + + while let Some(c) = template_iter.next() { + if c == '{' { + if let Some(nc) = template_iter.next() { + if nc == '{' { + filled_template.push('{'); + } else if nc == '}' { + if let Some(arg) = arg_iter.next() { + filled_template.push_str(&arg); + } else { + filled_template.push(c); + filled_template.push(nc); + } + } else if let Some(n) = nc.to_digit(10) { + filled_template.push_str(&args[n as usize].to_string()); + } else { + filled_template.push(nc); + } + } + } else if c == '}' { + if let Some(nc) = template_iter.next() { + if nc == '}' { + filled_template.push('}'); + continue; + } else { + filled_template.push(nc); + } + } + } else { + filled_template.push(c); + } + } + + filled_template +} + pub fn home_dir() -> Option { home_dir_inner() } @@ -954,7 +1009,7 @@ pub mod mock_time { use std::cell::RefCell; thread_local! { - static DATE_TIME_DIFF: RefCell> = RefCell::new(None); + static DATE_TIME_DIFF: RefCell> = const { RefCell::new(None) }; } pub fn time_now() -> DateTime { diff --git a/scripts/build.sh b/scripts/build.sh index 4f1c250a..769c09cc 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -36,7 +36,7 @@ for target in "${targets[@]}"; do cp ./target/${target}/release/ffpapi.exe . cp ./target/${target}/release/ffplayout.exe . - zip -r "ffplayout-v${version}_${target}.zip" assets docker docs LICENSE README.md CHANGELOG.md ffplayout.exe ffpapi.exe -x *.db + zip -r "ffplayout-v${version}_${target}.zip" assets docker docs LICENSE README.md CHANGELOG.md ffplayout.exe ffpapi.exe -x *.db -x *.db-shm -x *.db-wal -x '11-ffplayout' -x *.service rm -f ffplayout.exe ffpapi.exe elif [[ $target == "x86_64-apple-darwin" ]] || [[ $target == "aarch64-apple-darwin" ]]; then if [[ -f "ffplayout-v${version}_${target}.tar.gz" ]]; then @@ -54,7 +54,7 @@ for target in "${targets[@]}"; do cp ./target/${target}/release/ffpapi . cp ./target/${target}/release/ffplayout . - tar -czvf "ffplayout-v${version}_${target}.tar.gz" --exclude='*.db' --exclude='*.db-shm' --exclude='*.db-wal' assets docker docs LICENSE README.md CHANGELOG.md ffplayout ffpapi + tar -czvf "ffplayout-v${version}_${target}.tar.gz" --exclude='*.db' --exclude='*.db-shm' --exclude='*.db-wal' --exclude='11-ffplayout' --exclude='*.service' assets docker docs LICENSE README.md CHANGELOG.md ffplayout ffpapi rm -f ffplayout ffpapi else if [[ -f "ffplayout-v${version}_${target}.tar.gz" ]]; then @@ -72,11 +72,11 @@ for target in "${targets[@]}"; do echo "" done -if [[ "${#targets[@]}" == "3" ]] || [[ $targets == "x86_64-unknown-linux-musl" ]]; then +if [[ "${#targets[@]}" == "5" ]] || [[ $targets == "x86_64-unknown-linux-musl" ]]; then cargo deb --target=x86_64-unknown-linux-musl -p ffplayout --manifest-path=ffplayout-engine/Cargo.toml -o ffplayout_${version}-1_amd64.deb cargo generate-rpm --payload-compress none --target=x86_64-unknown-linux-musl -p ffplayout-engine -o ffplayout-${version}-1.x86_64.rpm fi -if [[ "${#targets[@]}" == "3" ]] || [[ $targets == "aarch64-unknown-linux-gnu" ]]; then +if [[ "${#targets[@]}" == "5" ]] || [[ $targets == "aarch64-unknown-linux-gnu" ]]; then cargo deb --target=aarch64-unknown-linux-gnu --variant=arm64 -p ffplayout --manifest-path=ffplayout-engine/Cargo.toml -o ffplayout_${version}-1_arm64.deb fi diff --git a/tests/Cargo.toml b/tests/Cargo.toml index e5d6f1df..e8fe9ae0 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -20,7 +20,7 @@ lettre = { version = "0.11", features = ["builder", "rustls-tls", "smtp-transpor log = "0.4" rand = "0.8" regex = "1" -reqwest = { version = "0.11", default-features = false, features = ["blocking", "json", "rustls-tls"] } +reqwest = { version = "0.12", default-features = false, features = ["blocking", "json", "rustls-tls"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde_yaml = "0.9" diff --git a/tests/assets/playlists/2024/03/2024-03-19.json b/tests/assets/playlists/2024/03/2024-03-19.json new file mode 100644 index 00000000..2952577d --- /dev/null +++ b/tests/assets/playlists/2024/03/2024-03-19.json @@ -0,0 +1,288 @@ +{ + "channel": "Test 1", + "date": "2024-02-01", + "program": [ + { + "in": 0, + "out": 10.0, + "duration": 10.0, + "source": "tests/assets/media_sorted/DarkGray_00-00-10.mp4" + }, + { + "in": 0, + "out": 30.0, + "duration": 30.0, + "source": "tests/assets/media_sorted/Olive_00-00-30.mp4" + }, + { + "in": 0, + "out": 15.0, + "duration": 15.0, + "source": "tests/assets/media_sorted/Indigo_00-00-15.mp4" + }, + { + "in": 0, + "out": 25.0, + "duration": 25.0, + "source": "tests/assets/media_sorted/DarkOrchid_00-00-25.mp4" + }, + { + "in": 0, + "out": 45.0, + "duration": 45.0, + "source": "tests/assets/media_sorted/Orange_00-00-45.mp4" + }, + { + "in": 0, + "out": 20.0, + "duration": 20.0, + "source": "tests/assets/media_sorted/LightGoldenRodYellow_00-00-20.mp4" + }, + { + "in": 0, + "out": 30.0, + "duration": 30.0, + "source": "tests/assets/media_sorted/Cyan_00-00-30.mp4" + }, + { + "in": 0, + "out": 50.0, + "duration": 50.0, + "source": "tests/assets/media_sorted/Cornsilk_00-00-50.mp4" + }, + { + "in": 0, + "out": 15.0, + "duration": 15.0, + "source": "tests/assets/media_sorted/LightSeaGreen_00-00-15.mp4" + }, + { + "in": 0, + "out": 30.0, + "duration": 30.0, + "source": "tests/assets/media_sorted/Yellow_00-00-30.mp4" + }, + { + "in": 0, + "out": 30.0, + "duration": 30.0, + "source": "tests/assets/media_sorted/Aqua_00-00-30.mp4" + }, + { + "in": 0, + "out": 1500.0, + "duration": 1500.0, + "source": "tests/assets/media_sorted/MediumSeaGreen_00-25-00.mp4" + }, + { + "in": 0, + "out": 1800.0, + "duration": 1800.0, + "source": "tests/assets/media_sorted/MediumOrchid_00-30-00.mp4" + }, + { + "in": 0, + "out": 3600.0, + "duration": 3600.0, + "source": "tests/assets/media_sorted/IndianRed_01-00-00.mp4" + }, + { + "in": 0, + "out": 3600.0, + "duration": 3600.0, + "source": "tests/assets/media_sorted/ForestGreen_01-00-00.mp4" + }, + { + "in": 0, + "out": 3600.0, + "duration": 3600.0, + "source": "tests/assets/media_sorted/Plum_01-00-00.mp4" + }, + { + "in": 0, + "out": 3600.0, + "duration": 3600.0, + "source": "tests/assets/media_sorted/IndianRed_01-00-00.mp4" + }, + { + "in": 0, + "out": 3600.0, + "duration": 3600.0, + "source": "tests/assets/media_sorted/ForestGreen_01-00-00.mp4" + }, + { + "in": 0, + "out": 3600.0, + "duration": 3600.0, + "source": "tests/assets/media_sorted/Plum_01-00-00.mp4" + }, + { + "in": 0, + "out": 3600.0, + "duration": 3600.0, + "source": "tests/assets/media_sorted/IndianRed_01-00-00.mp4" + }, + { + "in": 0, + "out": 3600.0, + "duration": 3600.0, + "source": "tests/assets/media_sorted/ForestGreen_01-00-00.mp4" + }, + { + "in": 0, + "out": 3600.0, + "duration": 3600.0, + "source": "tests/assets/media_sorted/Plum_01-00-00.mp4" + }, + { + "in": 0, + "out": 3600.0, + "duration": 3600.0, + "source": "tests/assets/media_sorted/IndianRed_01-00-00.mp4" + }, + { + "in": 0, + "out": 3600.0, + "duration": 3600.0, + "source": "tests/assets/media_sorted/ForestGreen_01-00-00.mp4" + }, + { + "in": 0, + "out": 3600.0, + "duration": 3600.0, + "source": "tests/assets/media_sorted/Plum_01-00-00.mp4" + }, + { + "in": 0, + "out": 3600.0, + "duration": 3600.0, + "source": "tests/assets/media_sorted/IndianRed_01-00-00.mp4" + }, + { + "in": 0, + "out": 3600.0, + "duration": 3600.0, + "source": "tests/assets/media_sorted/ForestGreen_01-00-00.mp4" + }, + { + "in": 0, + "out": 3600.0, + "duration": 3600.0, + "source": "tests/assets/media_sorted/Plum_01-00-00.mp4" + }, + { + "in": 0, + "out": 3600.0, + "duration": 3600.0, + "source": "tests/assets/media_sorted/IndianRed_01-00-00.mp4" + }, + { + "in": 0, + "out": 3600.0, + "duration": 3600.0, + "source": "tests/assets/media_sorted/ForestGreen_01-00-00.mp4" + }, + { + "in": 0, + "out": 3600.0, + "duration": 3600.0, + "source": "tests/assets/media_sorted/Plum_01-00-00.mp4" + }, + { + "in": 0, + "out": 3600.0, + "duration": 3600.0, + "source": "tests/assets/media_sorted/IndianRed_01-00-00.mp4" + }, + { + "in": 0, + "out": 3600.0, + "duration": 3600.0, + "source": "tests/assets/media_sorted/ForestGreen_01-00-00.mp4" + }, + { + "in": 0, + "out": 3600.0, + "duration": 3600.0, + "source": "tests/assets/media_sorted/Plum_01-00-00.mp4" + }, + { + "in": 0, + "out": 3600.0, + "duration": 3600.0, + "source": "tests/assets/media_sorted/IndianRed_01-00-00.mp4" + }, + { + "in": 0, + "out": 1800.0, + "duration": 1800.0, + "source": "tests/assets/media_sorted/MediumOrchid_00-30-00.mp4" + }, + { + "in": 0, + "out": 1500.0, + "duration": 1500.0, + "source": "tests/assets/media_sorted/MediumSeaGreen_00-25-00.mp4" + }, + { + "in": 0, + "out": 10.0, + "duration": 10.0, + "source": "tests/assets/media_sorted/DarkGray_00-00-10.mp4" + }, + { + "in": 0, + "out": 30.0, + "duration": 30.0, + "source": "tests/assets/media_sorted/Olive_00-00-30.mp4" + }, + { + "in": 0, + "out": 15.0, + "duration": 15.0, + "source": "tests/assets/media_sorted/Indigo_00-00-15.mp4" + }, + { + "in": 0, + "out": 25.0, + "duration": 25.0, + "source": "tests/assets/media_sorted/DarkOrchid_00-00-25.mp4" + }, + { + "in": 0, + "out": 45.0, + "duration": 45.0, + "source": "tests/assets/media_sorted/Orange_00-00-45.mp4" + }, + { + "in": 0, + "out": 20.0, + "duration": 20.0, + "source": "tests/assets/media_sorted/LightGoldenRodYellow_00-00-20.mp4" + }, + { + "in": 0, + "out": 30.0, + "duration": 30.0, + "source": "tests/assets/media_sorted/Cyan_00-00-30.mp4" + }, + { + "in": 0, + "out": 50.0, + "duration": 50.0, + "source": "tests/assets/media_sorted/Cornsilk_00-00-50.mp4" + }, + { + "in": 0, + "out": 15.0, + "duration": 15.0, + "source": "tests/assets/media_sorted/LightSeaGreen_00-00-15.mp4" + }, + { + "in": 0, + "out": 30.0, + "duration": 30.0, + "source": "tests/assets/media_sorted/Yellow_00-00-30.mp4" + } + ] +}