aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock878
-rw-r--r--Cargo.toml8
-rw-r--r--base/Cargo.toml10
-rw-r--r--base/src/database.rs21
-rw-r--r--base/src/permission.rs6
-rw-r--r--client/Cargo.toml6
-rw-r--r--client/src/lib.rs32
-rw-r--r--common/Cargo.toml4
-rw-r--r--common/src/impl.rs124
-rw-r--r--common/src/jhls.rs4
-rw-r--r--common/src/lib.rs252
-rw-r--r--ebml_derive/Cargo.toml4
-rw-r--r--import/Cargo.toml6
-rw-r--r--import/src/db.rs208
-rw-r--r--import/src/lib.rs1551
-rw-r--r--matroska/Cargo.toml6
-rw-r--r--remuxer/Cargo.toml6
-rw-r--r--remuxer/src/fragment.rs6
-rw-r--r--remuxer/src/metadata.rs12
-rw-r--r--remuxer/src/remux.rs8
-rw-r--r--server/Cargo.toml16
-rw-r--r--server/src/routes/mod.rs13
-rw-r--r--server/src/routes/stream.rs11
-rw-r--r--server/src/routes/ui/admin/log.rs4
-rw-r--r--server/src/routes/ui/admin/mod.rs75
-rw-r--r--server/src/routes/ui/assets.rs70
-rw-r--r--server/src/routes/ui/browser.rs1
-rw-r--r--server/src/routes/ui/home.rs34
-rw-r--r--server/src/routes/ui/node.rs112
-rw-r--r--server/src/routes/ui/player.rs13
-rw-r--r--server/src/routes/ui/search.rs3
-rw-r--r--server/src/routes/ui/sort.rs4
-rw-r--r--stream/Cargo.toml6
-rw-r--r--stream/src/fragment.rs6
-rw-r--r--stream/src/hls.rs11
-rw-r--r--stream/src/jhls.rs7
-rw-r--r--stream/src/lib.rs12
-rw-r--r--stream/src/webvtt.rs9
-rw-r--r--tool/Cargo.toml16
-rw-r--r--tool/src/add.rs68
-rw-r--r--transcoder/Cargo.toml4
-rw-r--r--transcoder/src/image.rs2
-rw-r--r--transcoder/src/lib.rs2
43 files changed, 1848 insertions, 1803 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 1f3841a..9fb643c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -84,9 +84,9 @@ checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1"
[[package]]
name = "allocator-api2"
-version = "0.2.18"
+version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
+checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]]
name = "android-tzdata"
@@ -105,9 +105,9 @@ dependencies = [
[[package]]
name = "anstream"
-version = "0.6.17"
+version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338"
+checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
dependencies = [
"anstyle",
"anstyle-parse",
@@ -120,9 +120,9 @@ dependencies = [
[[package]]
name = "anstyle"
-version = "1.0.9"
+version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8365de52b16c035ff4fcafe0092ba9390540e3e352870ac09933bebcaa2c8c56"
+checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
[[package]]
name = "anstyle-parse"
@@ -144,25 +144,26 @@ dependencies = [
[[package]]
name = "anstyle-wincon"
-version = "3.0.6"
+version = "3.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
+checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
dependencies = [
"anstyle",
+ "once_cell",
"windows-sys 0.59.0",
]
[[package]]
name = "anyhow"
-version = "1.0.92"
+version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74f37166d7d48a0284b99dd824694c26119c700b53bf0d1540cdb147dbdaaf13"
+checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
[[package]]
name = "arbitrary"
-version = "1.3.2"
+version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
+checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223"
[[package]]
name = "arc-swap"
@@ -353,9 +354,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
-version = "2.6.0"
+version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
[[package]]
name = "bitpacking"
@@ -368,9 +369,9 @@ dependencies = [
[[package]]
name = "bitstream-io"
-version = "2.5.3"
+version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b81e1519b0d82120d2fd469d5bfb2919a9361c48b02d82d04befc1cdd2002452"
+checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2"
[[package]]
name = "blake2"
@@ -404,9 +405,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
[[package]]
name = "bytemuck"
-version = "1.19.0"
+version = "1.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d"
+checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3"
[[package]]
name = "byteorder"
@@ -422,15 +423,15 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
[[package]]
name = "bytes"
-version = "1.8.0"
+version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da"
+checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
[[package]]
name = "cc"
-version = "1.1.31"
+version = "1.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f"
+checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229"
dependencies = [
"jobserver",
"libc",
@@ -477,9 +478,9 @@ dependencies = [
[[package]]
name = "chrono"
-version = "0.4.38"
+version = "0.4.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
+checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
dependencies = [
"android-tzdata",
"iana-time-zone",
@@ -502,9 +503,9 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.5.20"
+version = "4.5.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8"
+checksum = "769b0145982b4b48713e01ec42d61614425f27b7058bda7180a3a41f30104796"
dependencies = [
"clap_builder",
"clap_derive",
@@ -512,9 +513,9 @@ dependencies = [
[[package]]
name = "clap_builder"
-version = "4.5.20"
+version = "4.5.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54"
+checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7"
dependencies = [
"anstream",
"anstyle",
@@ -524,18 +525,18 @@ dependencies = [
[[package]]
name = "clap_complete"
-version = "4.5.36"
+version = "4.5.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86bc73de94bc81e52f3bebec71bc4463e9748f7a59166663e32044669577b0e2"
+checksum = "0952013545c9c6dca60f491602655b795c6c062ab180c9cb0bccb83135461861"
dependencies = [
"clap",
]
[[package]]
name = "clap_derive"
-version = "4.5.18"
+version = "4.5.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
+checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c"
dependencies = [
"heck",
"proc-macro2",
@@ -545,9 +546,9 @@ dependencies = [
[[package]]
name = "clap_lex"
-version = "0.7.2"
+version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
+checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
[[package]]
name = "cmake"
@@ -572,15 +573,15 @@ checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]]
name = "console"
-version = "0.15.8"
+version = "0.15.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb"
+checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b"
dependencies = [
"encode_unicode",
- "lazy_static",
"libc",
+ "once_cell",
"unicode-width",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -635,9 +636,9 @@ dependencies = [
[[package]]
name = "crossbeam-deque"
-version = "0.8.5"
+version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
+checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
@@ -654,15 +655,15 @@ dependencies = [
[[package]]
name = "crossbeam-utils"
-version = "0.8.20"
+version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]]
name = "crunchy"
-version = "0.2.2"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
+checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929"
[[package]]
name = "crypto-common"
@@ -726,7 +727,7 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b035a542cf7abf01f2e3c4d5a7acbaebfefe120ae4efc7bde3df98186e4b8af7"
dependencies = [
- "bitflags 2.6.0",
+ "bitflags 2.8.0",
"proc-macro2",
"proc-macro2-diagnostics",
"quote",
@@ -743,7 +744,7 @@ dependencies = [
"fuzzy-matcher",
"shell-words",
"tempfile",
- "thiserror",
+ "thiserror 1.0.69",
"zeroize",
]
@@ -759,6 +760,17 @@ dependencies = [
]
[[package]]
+name = "displaydoc"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "downcast-rs"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -780,9 +792,9 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "encode_unicode"
-version = "0.3.6"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
+checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
[[package]]
name = "encoding_rs"
@@ -795,9 +807,9 @@ dependencies = [
[[package]]
name = "env_filter"
-version = "0.1.2"
+version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab"
+checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
dependencies = [
"log",
"regex",
@@ -805,9 +817,9 @@ dependencies = [
[[package]]
name = "env_logger"
-version = "0.11.5"
+version = "0.11.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d"
+checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0"
dependencies = [
"anstream",
"anstyle",
@@ -861,9 +873,9 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
[[package]]
name = "fdeflate"
-version = "0.3.6"
+version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07c6f4c64c1d33a3111c4466f7365ebdcc37c5bd1ea0d62aae2e3d722aacbedb"
+checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
dependencies = [
"simd-adler32",
]
@@ -884,9 +896,9 @@ dependencies = [
[[package]]
name = "flate2"
-version = "1.0.34"
+version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0"
+checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c"
dependencies = [
"crc32fast",
"miniz_oxide",
@@ -900,9 +912,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foldhash"
-version = "0.1.3"
+version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
+checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
[[package]]
name = "form_urlencoded"
@@ -1057,8 +1069,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
+ "js-sys",
+ "libc",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
+dependencies = [
+ "cfg-if",
"libc",
- "wasi",
+ "wasi 0.13.3+wasi-0.2.2",
+ "windows-targets 0.52.6",
]
[[package]]
@@ -1089,9 +1115,9 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]]
name = "glob"
-version = "0.3.1"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
+checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
[[package]]
name = "h2"
@@ -1124,9 +1150,9 @@ dependencies = [
[[package]]
name = "hashbrown"
-version = "0.15.0"
+version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
+checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
dependencies = [
"allocator-api2",
"equivalent",
@@ -1188,9 +1214,9 @@ dependencies = [
[[package]]
name = "http"
-version = "1.1.0"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
+checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea"
dependencies = [
"bytes",
"fnv",
@@ -1215,7 +1241,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
dependencies = [
"bytes",
- "http 1.1.0",
+ "http 1.2.0",
]
[[package]]
@@ -1226,7 +1252,7 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
dependencies = [
"bytes",
"futures-util",
- "http 1.1.0",
+ "http 1.2.0",
"http-body 1.0.1",
"pin-project-lite",
]
@@ -1284,14 +1310,14 @@ dependencies = [
[[package]]
name = "hyper"
-version = "1.5.0"
+version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a"
+checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0"
dependencies = [
"bytes",
"futures-channel",
"futures-util",
- "http 1.1.0",
+ "http 1.2.0",
"http-body 1.0.1",
"httparse",
"itoa",
@@ -1303,13 +1329,13 @@ dependencies = [
[[package]]
name = "hyper-rustls"
-version = "0.27.3"
+version = "0.27.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333"
+checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2"
dependencies = [
"futures-util",
- "http 1.1.0",
- "hyper 1.5.0",
+ "http 1.2.0",
+ "hyper 1.5.2",
"hyper-util",
"rustls",
"rustls-pki-types",
@@ -1328,9 +1354,9 @@ dependencies = [
"bytes",
"futures-channel",
"futures-util",
- "http 1.1.0",
+ "http 1.2.0",
"http-body 1.0.1",
- "hyper 1.5.0",
+ "hyper 1.5.2",
"pin-project-lite",
"socket2",
"tokio",
@@ -1362,20 +1388,149 @@ dependencies = [
]
[[package]]
+name = "icu_collections"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
+dependencies = [
+ "displaydoc",
+ "litemap",
+ "tinystr",
+ "writeable",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid_transform"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
+dependencies = [
+ "displaydoc",
+ "icu_locid",
+ "icu_locid_transform_data",
+ "icu_provider",
+ "tinystr",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid_transform_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
+
+[[package]]
+name = "icu_normalizer"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_normalizer_data",
+ "icu_properties",
+ "icu_provider",
+ "smallvec 1.13.2",
+ "utf16_iter",
+ "utf8_iter",
+ "write16",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
+
+[[package]]
+name = "icu_properties"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_locid_transform",
+ "icu_properties_data",
+ "icu_provider",
+ "tinystr",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_properties_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
+
+[[package]]
+name = "icu_provider"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
+dependencies = [
+ "displaydoc",
+ "icu_locid",
+ "icu_provider_macros",
+ "stable_deref_trait",
+ "tinystr",
+ "writeable",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_provider_macros"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "idna"
-version = "0.5.0"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
+dependencies = [
+ "idna_adapter",
+ "smallvec 1.13.2",
+ "utf8_iter",
+]
+
+[[package]]
+name = "idna_adapter"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
+checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
dependencies = [
- "unicode-bidi",
- "unicode-normalization",
+ "icu_normalizer",
+ "icu_properties",
]
[[package]]
name = "image"
-version = "0.25.4"
+version = "0.25.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc144d44a31d753b02ce64093d532f55ff8dc4ebf2ffb8a63c0dda691385acae"
+checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b"
dependencies = [
"bytemuck",
"byteorder-lite",
@@ -1396,9 +1551,9 @@ dependencies = [
[[package]]
name = "image-webp"
-version = "0.2.0"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e031e8e3d94711a9ccb5d6ea357439ef3dcbed361798bd4071dc4d9793fbe22f"
+checksum = "b77d01e822461baa8409e156015a1d91735549f0f2c17691bd2d996bef238f7f"
dependencies = [
"byteorder-lite",
"quick-error",
@@ -1412,9 +1567,9 @@ checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408"
[[package]]
name = "indexmap"
-version = "2.6.0"
+version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
+checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
dependencies = [
"equivalent",
"hashbrown",
@@ -1423,15 +1578,15 @@ dependencies = [
[[package]]
name = "indicatif"
-version = "0.17.8"
+version = "0.17.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3"
+checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235"
dependencies = [
"console",
- "instant",
"number_prefix",
"portable-atomic",
"unicode-width",
+ "web-time",
]
[[package]]
@@ -1506,9 +1661,9 @@ dependencies = [
[[package]]
name = "itoa"
-version = "1.0.11"
+version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
[[package]]
name = "jellybase"
@@ -1521,7 +1676,7 @@ dependencies = [
"jellyclient",
"jellycommon",
"log",
- "rand 0.8.5",
+ "rand 0.9.0",
"redb",
"serde",
"serde_json",
@@ -1585,7 +1740,7 @@ dependencies = [
"ebml_derive",
"env_logger",
"log",
- "thiserror",
+ "thiserror 2.0.11",
]
[[package]]
@@ -1640,7 +1795,7 @@ dependencies = [
"jellytranscoder",
"log",
"markup",
- "rand 0.8.5",
+ "rand 0.9.0",
"rocket",
"rocket_ws",
"serde",
@@ -1667,7 +1822,7 @@ dependencies = [
"jellycommon",
"jellyimport",
"log",
- "rand 0.8.5",
+ "rand 0.9.0",
"reqwest",
"serde",
"serde_json",
@@ -1711,10 +1866,11 @@ checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0"
[[package]]
name = "js-sys"
-version = "0.3.72"
+version = "0.3.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9"
+checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
dependencies = [
+ "once_cell",
"wasm-bindgen",
]
@@ -1768,9 +1924,9 @@ dependencies = [
[[package]]
name = "libc"
-version = "0.2.161"
+version = "0.2.169"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
+checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
[[package]]
name = "libdav1d-sys"
@@ -1783,13 +1939,12 @@ dependencies = [
[[package]]
name = "libfuzzer-sys"
-version = "0.4.7"
+version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7"
+checksum = "9b9569d2f74e257076d8c6bfa73fb505b46b851e51ddaecc825944aa3bed17fa"
dependencies = [
"arbitrary",
"cc",
- "once_cell",
]
[[package]]
@@ -1805,6 +1960,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
[[package]]
+name = "litemap"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
+
+[[package]]
name = "lock_api"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1816,9 +1977,9 @@ dependencies = [
[[package]]
name = "log"
-version = "0.4.22"
+version = "0.4.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
[[package]]
name = "loom"
@@ -1943,9 +2104,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniz_oxide"
-version = "0.8.0"
+version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
+checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924"
dependencies = [
"adler2",
"simd-adler32",
@@ -1953,13 +2114,12 @@ dependencies = [
[[package]]
name = "mio"
-version = "1.0.2"
+version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
+checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
dependencies = [
- "hermit-abi 0.3.9",
"libc",
- "wasi",
+ "wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys 0.52.0",
]
@@ -1972,7 +2132,7 @@ dependencies = [
"bytes",
"encoding_rs",
"futures-util",
- "http 1.1.0",
+ "http 1.2.0",
"httparse",
"memchr",
"mime",
@@ -2104,9 +2264,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]]
name = "object"
-version = "0.36.5"
+version = "0.36.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e"
+checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
dependencies = [
"memchr",
]
@@ -2246,9 +2406,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "pin-project-lite"
-version = "0.2.15"
+version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
+checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
[[package]]
name = "pin-utils"
@@ -2264,9 +2424,9 @@ checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]]
name = "png"
-version = "0.17.14"
+version = "0.17.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52f9d46a34a05a6a57566bc2bfae066ef07585a6e3fa30fbbdff5936380623f0"
+checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526"
dependencies = [
"bitflags 1.3.2",
"crc32fast",
@@ -2289,9 +2449,9 @@ dependencies = [
[[package]]
name = "portable-atomic"
-version = "1.9.0"
+version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
+checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6"
[[package]]
name = "powerfmt"
@@ -2305,14 +2465,14 @@ version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
dependencies = [
- "zerocopy",
+ "zerocopy 0.7.35",
]
[[package]]
name = "proc-macro2"
-version = "1.0.89"
+version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
+checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
dependencies = [
"unicode-ident",
]
@@ -2366,44 +2526,47 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
[[package]]
name = "quinn"
-version = "0.11.5"
+version = "0.11.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684"
+checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef"
dependencies = [
"bytes",
"pin-project-lite",
"quinn-proto",
"quinn-udp",
- "rustc-hash 2.0.0",
+ "rustc-hash 2.1.0",
"rustls",
"socket2",
- "thiserror",
+ "thiserror 2.0.11",
"tokio",
"tracing",
]
[[package]]
name = "quinn-proto"
-version = "0.11.8"
+version = "0.11.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6"
+checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d"
dependencies = [
"bytes",
+ "getrandom 0.2.15",
"rand 0.8.5",
"ring",
- "rustc-hash 2.0.0",
+ "rustc-hash 2.1.0",
"rustls",
+ "rustls-pki-types",
"slab",
- "thiserror",
+ "thiserror 2.0.11",
"tinyvec",
"tracing",
+ "web-time",
]
[[package]]
name = "quinn-udp"
-version = "0.5.6"
+version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e346e016eacfff12233c243718197ca12f148c84e1e84268a896699b41c71780"
+checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904"
dependencies = [
"cfg_aliases",
"libc",
@@ -2415,9 +2578,9 @@ dependencies = [
[[package]]
name = "quote"
-version = "1.0.37"
+version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
+checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
dependencies = [
"proc-macro2",
]
@@ -2442,11 +2605,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
- "rand_chacha",
+ "rand_chacha 0.3.1",
"rand_core 0.6.4",
]
[[package]]
+name = "rand"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
+dependencies = [
+ "rand_chacha 0.9.0",
+ "rand_core 0.9.0",
+ "zerocopy 0.8.14",
+]
+
+[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2457,6 +2631,16 @@ dependencies = [
]
[[package]]
+name = "rand_chacha"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.9.0",
+]
+
+[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2477,7 +2661,17 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
- "getrandom",
+ "getrandom 0.2.15",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff"
+dependencies = [
+ "getrandom 0.3.1",
+ "zerocopy 0.8.14",
]
[[package]]
@@ -2519,10 +2713,10 @@ dependencies = [
"paste",
"profiling",
"rand 0.8.5",
- "rand_chacha",
+ "rand_chacha 0.3.1",
"simd_helpers",
"system-deps",
- "thiserror",
+ "thiserror 1.0.69",
"v_frame",
"wasm-bindgen",
]
@@ -2573,20 +2767,20 @@ dependencies = [
[[package]]
name = "redb"
-version = "2.2.0"
+version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84b1de48a7cf7ba193e81e078d17ee2b786236eed1d3f7c60f8a09545efc4925"
+checksum = "ea0a72cd7140de9fc3e318823b883abf819c20d478ec89ce880466dc2ef263c6"
dependencies = [
"libc",
]
[[package]]
name = "redox_syscall"
-version = "0.5.7"
+version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
+checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
dependencies = [
- "bitflags 2.6.0",
+ "bitflags 2.8.0",
]
[[package]]
@@ -2617,7 +2811,7 @@ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
- "regex-automata 0.4.8",
+ "regex-automata 0.4.9",
"regex-syntax 0.8.5",
]
@@ -2632,9 +2826,9 @@ dependencies = [
[[package]]
name = "regex-automata"
-version = "0.4.8"
+version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
+checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
@@ -2655,19 +2849,19 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "reqwest"
-version = "0.12.9"
+version = "0.12.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f"
+checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da"
dependencies = [
"base64",
"bytes",
"futures-channel",
"futures-core",
"futures-util",
- "http 1.1.0",
+ "http 1.2.0",
"http-body 1.0.1",
"http-body-util",
- "hyper 1.5.0",
+ "hyper 1.5.2",
"hyper-rustls",
"hyper-util",
"ipnet",
@@ -2687,6 +2881,7 @@ dependencies = [
"sync_wrapper",
"tokio",
"tokio-rustls",
+ "tower",
"tower-service",
"url",
"wasm-bindgen",
@@ -2713,7 +2908,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
dependencies = [
"cc",
"cfg-if",
- "getrandom",
+ "getrandom 0.2.15",
"libc",
"spin",
"untrusted",
@@ -2836,9 +3031,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustc-hash"
-version = "2.0.0"
+version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
+checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497"
[[package]]
name = "rustix"
@@ -2846,7 +3041,7 @@ version = "0.38.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a"
dependencies = [
- "bitflags 2.6.0",
+ "bitflags 2.8.0",
"errno",
"libc",
"linux-raw-sys",
@@ -2855,9 +3050,9 @@ dependencies = [
[[package]]
name = "rustls"
-version = "0.23.16"
+version = "0.23.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e"
+checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b"
dependencies = [
"once_cell",
"ring",
@@ -2878,9 +3073,12 @@ dependencies = [
[[package]]
name = "rustls-pki-types"
-version = "1.10.0"
+version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b"
+checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37"
+dependencies = [
+ "web-time",
+]
[[package]]
name = "rustls-webpki"
@@ -2919,18 +3117,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "serde"
-version = "1.0.214"
+version = "1.0.217"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5"
+checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.214"
+version = "1.0.217"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766"
+checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
dependencies = [
"proc-macro2",
"quote",
@@ -2939,9 +3137,9 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.132"
+version = "1.0.138"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03"
+checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949"
dependencies = [
"itoa",
"memchr",
@@ -3085,9 +3283,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "socket2"
-version = "0.5.7"
+version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
+checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
dependencies = [
"libc",
"windows-sys 0.52.0",
@@ -3137,9 +3335,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
-version = "2.0.86"
+version = "2.0.96"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e89275301d38033efb81a6e60e3497e734dfcc62571f2854bf4b16690398824c"
+checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80"
dependencies = [
"proc-macro2",
"quote",
@@ -3148,14 +3346,25 @@ dependencies = [
[[package]]
name = "sync_wrapper"
-version = "1.0.1"
+version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
+checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
dependencies = [
"futures-core",
]
[[package]]
+name = "synstructure"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "system-deps"
version = "6.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3213,7 +3422,7 @@ dependencies = [
"tantivy-stacker",
"tantivy-tokenizer-api",
"tempfile",
- "thiserror",
+ "thiserror 1.0.69",
"time",
"uuid",
"winapi",
@@ -3330,18 +3539,38 @@ dependencies = [
[[package]]
name = "thiserror"
-version = "1.0.66"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
+dependencies = [
+ "thiserror-impl 1.0.69",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d171f59dbaa811dbbb1aee1e73db92ec2b122911a48e1390dfe327a821ddede"
+checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc"
dependencies = [
- "thiserror-impl",
+ "thiserror-impl 2.0.11",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.66"
+version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b08be0f17bd307950653ce45db00cd31200d82b624b36e181337d9c7d92765b5"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2"
dependencies = [
"proc-macro2",
"quote",
@@ -3401,10 +3630,20 @@ dependencies = [
]
[[package]]
+name = "tinystr"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
+dependencies = [
+ "displaydoc",
+ "zerovec",
+]
+
+[[package]]
name = "tinyvec"
-version = "1.8.0"
+version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938"
+checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8"
dependencies = [
"tinyvec_macros",
]
@@ -3417,9 +3656,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
-version = "1.41.0"
+version = "1.43.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb"
+checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e"
dependencies = [
"backtrace",
"bytes",
@@ -3435,9 +3674,9 @@ dependencies = [
[[package]]
name = "tokio-macros"
-version = "2.4.0"
+version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
+checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
dependencies = [
"proc-macro2",
"quote",
@@ -3446,12 +3685,11 @@ dependencies = [
[[package]]
name = "tokio-rustls"
-version = "0.26.0"
+version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
+checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37"
dependencies = [
"rustls",
- "rustls-pki-types",
"tokio",
]
@@ -3480,9 +3718,9 @@ dependencies = [
[[package]]
name = "tokio-util"
-version = "0.7.12"
+version = "0.7.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a"
+checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078"
dependencies = [
"bytes",
"futures-core",
@@ -3526,6 +3764,27 @@ dependencies = [
]
[[package]]
+name = "tower"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
+dependencies = [
+ "futures-core",
+ "futures-util",
+ "pin-project-lite",
+ "sync_wrapper",
+ "tokio",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
+name = "tower-layer"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
+
+[[package]]
name = "tower-service"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3533,9 +3792,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
[[package]]
name = "tracing"
-version = "0.1.40"
+version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
+checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
dependencies = [
"pin-project-lite",
"tracing-attributes",
@@ -3544,9 +3803,9 @@ dependencies = [
[[package]]
name = "tracing-attributes"
-version = "0.1.27"
+version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
+checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
dependencies = [
"proc-macro2",
"quote",
@@ -3555,9 +3814,9 @@ dependencies = [
[[package]]
name = "tracing-core"
-version = "0.1.32"
+version = "0.1.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
+checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
dependencies = [
"once_cell",
"valuable",
@@ -3607,12 +3866,12 @@ dependencies = [
"byteorder",
"bytes",
"data-encoding",
- "http 1.1.0",
+ "http 1.2.0",
"httparse",
"log",
"rand 0.8.5",
"sha1",
- "thiserror",
+ "thiserror 1.0.69",
"url",
"utf-8",
]
@@ -3643,31 +3902,16 @@ dependencies = [
]
[[package]]
-name = "unicode-bidi"
-version = "0.3.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893"
-
-[[package]]
name = "unicode-ident"
-version = "1.0.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
-
-[[package]]
-name = "unicode-normalization"
-version = "0.1.24"
+version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956"
-dependencies = [
- "tinyvec",
-]
+checksum = "11cd88e12b17c6494200a9c1b683a04fcac9573ed74cd1b62aeb2727c5592243"
[[package]]
name = "unicode-width"
-version = "0.1.14"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
+checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
[[package]]
name = "unicode-xid"
@@ -3699,9 +3943,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "url"
-version = "2.5.2"
+version = "2.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
+checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
dependencies = [
"form_urlencoded",
"idna",
@@ -3721,12 +3965,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
+name = "utf16_iter"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
+
+[[package]]
name = "utf8-ranges"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba"
[[package]]
+name = "utf8_iter"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
+
+[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3738,7 +3994,7 @@ version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a"
dependencies = [
- "getrandom",
+ "getrandom 0.2.15",
"serde",
]
@@ -3779,23 +4035,12 @@ checksum = "9dcc60c0624df774c82a0ef104151231d37da4962957d691c011c852b2473314"
[[package]]
name = "vte"
-version = "0.13.0"
+version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "40eb22ae96f050e0c0d6f7ce43feeae26c348fc4dea56928ca81537cfaa6188b"
+checksum = "231fdcd7ef3037e8330d8e17e61011a2c244126acc0a982f4040ac3f9f0bc077"
dependencies = [
"arrayvec",
- "utf8parse",
- "vte_generate_state_changes",
-]
-
-[[package]]
-name = "vte_generate_state_changes"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e"
-dependencies = [
- "proc-macro2",
- "quote",
+ "memchr",
]
[[package]]
@@ -3814,25 +4059,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
+name = "wasi"
+version = "0.13.3+wasi-0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
+dependencies = [
+ "wit-bindgen-rt",
+]
+
+[[package]]
name = "wasm-bindgen"
-version = "0.2.95"
+version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e"
+checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
dependencies = [
"cfg-if",
"once_cell",
+ "rustversion",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
-version = "0.2.95"
+version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358"
+checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
dependencies = [
"bumpalo",
"log",
- "once_cell",
"proc-macro2",
"quote",
"syn",
@@ -3841,21 +4095,22 @@ dependencies = [
[[package]]
name = "wasm-bindgen-futures"
-version = "0.4.45"
+version = "0.4.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b"
+checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61"
dependencies = [
"cfg-if",
"js-sys",
+ "once_cell",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.95"
+version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56"
+checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -3863,9 +4118,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.95"
+version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
+checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
dependencies = [
"proc-macro2",
"quote",
@@ -3876,15 +4131,28 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.95"
+version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
+checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+dependencies = [
+ "unicode-ident",
+]
[[package]]
name = "web-sys"
-version = "0.3.72"
+version = "0.3.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112"
+checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "web-time"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -4116,14 +4384,35 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
-version = "0.6.20"
+version = "0.6.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
+checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a"
dependencies = [
"memchr",
]
[[package]]
+name = "wit-bindgen-rt"
+version = "0.33.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
+dependencies = [
+ "bitflags 2.8.0",
+]
+
+[[package]]
+name = "write16"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
+
+[[package]]
+name = "writeable"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
+
+[[package]]
name = "yansi"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4133,13 +4422,46 @@ dependencies = [
]
[[package]]
+name = "yoke"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
+dependencies = [
+ "serde",
+ "stable_deref_trait",
+ "yoke-derive",
+ "zerofrom",
+]
+
+[[package]]
+name = "yoke-derive"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
+
+[[package]]
name = "zerocopy"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"byteorder",
- "zerocopy-derive",
+ "zerocopy-derive 0.7.35",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.8.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a367f292d93d4eab890745e75a778da40909cab4d6ff8173693812f79c4a2468"
+dependencies = [
+ "zerocopy-derive 0.8.14",
]
[[package]]
@@ -4154,12 +4476,66 @@ dependencies = [
]
[[package]]
+name = "zerocopy-derive"
+version = "0.8.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3931cb58c62c13adec22e38686b559c86a30565e16ad6e8510a337cedc611e1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "zerofrom"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e"
+dependencies = [
+ "zerofrom-derive",
+]
+
+[[package]]
+name = "zerofrom-derive"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
+
+[[package]]
name = "zeroize"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
[[package]]
+name = "zerovec"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
+dependencies = [
+ "yoke",
+ "zerofrom",
+ "zerovec-derive",
+]
+
+[[package]]
+name = "zerovec-derive"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "zstd"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4204,9 +4580,9 @@ dependencies = [
[[package]]
name = "zune-jpeg"
-version = "0.4.13"
+version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16099418600b4d8f028622f73ff6e3deaabdff330fb9a2a131dea781ee8b0768"
+checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028"
dependencies = [
"zune-core",
]
diff --git a/Cargo.toml b/Cargo.toml
index 60c2a26..dc31503 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -18,11 +18,11 @@ resolver = "2"
rocket = "0.5"
rocket_ws = "0.1"
-log = "0.4.22"
-anyhow = "1.0.92"
-tokio = { version = "1.41.0", features = ["full"] }
+log = "0.4.25"
+anyhow = "1.0.95"
+tokio = { version = "1.43.0", features = ["full"] }
-reqwest = { version = "0.12.9", default-features = false, features = [
+reqwest = { version = "0.12.12", default-features = false, features = [
"rustls-tls",
"json",
"blocking",
diff --git a/base/Cargo.toml b/base/Cargo.toml
index be32dce..b9e47de 100644
--- a/base/Cargo.toml
+++ b/base/Cargo.toml
@@ -6,18 +6,18 @@ edition = "2021"
[dependencies]
jellycommon = { path = "../common" }
jellyclient = { path = "../client" }
-serde = { version = "1.0.214", features = ["derive"] }
+serde = { version = "1.0.217", features = ["derive"] }
serde_yaml = "0.9.34"
log = { workspace = true }
sha2 = "0.10.8"
base64 = "0.22.1"
tokio = { workspace = true }
-anyhow = "1.0.92"
+anyhow = "1.0.95"
bincode = "2.0.0-rc.3"
-rand = "0.8.5"
-redb = "2.2.0"
+rand = "0.9.0"
+redb = "2.4.0"
tantivy = "0.22.0"
-serde_json = "1.0.132"
+serde_json = "1.0.138"
aes-gcm-siv = "0.11.1"
[features]
diff --git a/base/src/database.rs b/base/src/database.rs
index e57ea3e..a6bcdf7 100644
--- a/base/src/database.rs
+++ b/base/src/database.rs
@@ -7,7 +7,7 @@ use anyhow::Context;
use bincode::{Decode, Encode};
use jellycommon::{
user::{NodeUserData, User},
- ExtendedNode, Node,
+ Node,
};
use log::info;
use redb::{Database, TableDefinition};
@@ -33,11 +33,6 @@ pub const T_USER_NODE: TableDefinition<(&str, &str), Ser<NodeUserData>> =
TableDefinition::new("user_node");
pub const T_INVITE: TableDefinition<&str, Ser<()>> = TableDefinition::new("invite");
pub const T_NODE: TableDefinition<&str, Ser<Node>> = TableDefinition::new("node");
-pub const T_NODE_EXTENDED: TableDefinition<&str, Ser<ExtendedNode>> =
- TableDefinition::new("node-ext");
-#[allow(clippy::type_complexity)]
-pub const T_NODE_IMPORT: TableDefinition<&str, Ser<Vec<(Vec<usize>, Node)>>> =
- TableDefinition::new("node-import");
#[derive(Clone)]
pub struct DataAcid {
@@ -64,8 +59,6 @@ impl DataAcid {
drop(txn.open_table(T_USER)?);
drop(txn.open_table(T_USER_NODE)?);
drop(txn.open_table(T_NODE)?);
- drop(txn.open_table(T_NODE_IMPORT)?);
- drop(txn.open_table(T_NODE_EXTENDED)?);
txn.commit()?;
}
@@ -205,10 +198,12 @@ where
pub struct Ser<T>(pub T);
#[cfg(not(feature = "db_json"))]
impl<T: Encode + Decode + std::fmt::Debug> redb::Value for Ser<T> {
- type SelfType<'a> = Ser<T>
+ type SelfType<'a>
+ = Ser<T>
where
Self: 'a;
- type AsBytes<'a> = Vec<u8>
+ type AsBytes<'a>
+ = Vec<u8>
where
Self: 'a;
@@ -243,10 +238,12 @@ impl<T: Encode + Decode + std::fmt::Debug> redb::Value for Ser<T> {
pub struct Ser<T>(pub T);
#[cfg(feature = "db_json")]
impl<T: Serialize + for<'a> Deserialize<'a> + std::fmt::Debug> redb::Value for Ser<T> {
- type SelfType<'a> = Ser<T>
+ type SelfType<'a>
+ = Ser<T>
where
Self: 'a;
- type AsBytes<'a> = Vec<u8>
+ type AsBytes<'a>
+ = Vec<u8>
where
Self: 'a;
diff --git a/base/src/permission.rs b/base/src/permission.rs
index 358202f..11668a2 100644
--- a/base/src/permission.rs
+++ b/base/src/permission.rs
@@ -51,12 +51,10 @@ impl NodePermissionExt for Option<Node> {
}
}
fn check_node_permission(perms: &PermissionSet, node: &Node) -> bool {
- if let Some(v) =
- perms.check_explicit(&UserPermission::AccessNode(node.public.id.clone().unwrap()))
- {
+ if let Some(v) = perms.check_explicit(&UserPermission::AccessNode(node.id.clone().unwrap())) {
v
} else {
- for com in node.public.path.clone().into_iter().rev() {
+ for com in node.parents.clone().into_iter() {
if let Some(v) = perms.check_explicit(&UserPermission::AccessNode(com.to_owned())) {
return v;
}
diff --git a/client/Cargo.toml b/client/Cargo.toml
index b00fbc4..7368ac3 100644
--- a/client/Cargo.toml
+++ b/client/Cargo.toml
@@ -7,7 +7,7 @@ edition = "2021"
jellycommon = { path = "../common" }
log = { workspace = true }
reqwest = { workspace = true }
-anyhow = "1.0.92"
-serde_json = "1.0.132"
-serde = { version = "1.0.214", features = ["derive"] }
+anyhow = "1.0.95"
+serde_json = "1.0.138"
+serde = { version = "1.0.217", features = ["derive"] }
tokio = { workspace = true }
diff --git a/client/src/lib.rs b/client/src/lib.rs
index 50266ee..191db7a 100644
--- a/client/src/lib.rs
+++ b/client/src/lib.rs
@@ -71,7 +71,7 @@ impl Session {
format!("session={}", self.session_token)
}
- pub async fn node(&self, id: &str) -> Result<NodePublic> {
+ pub async fn node(&self, id: &str) -> Result<Node> {
debug!("downloading node {id:?}");
Ok(self
.client
@@ -82,36 +82,6 @@ impl Session {
.json()
.await?)
}
- pub async fn node_extended(&self, id: &str) -> Result<ExtendedNode> {
- debug!("downloading extended node {id:?}");
- Ok(self
- .client
- .get(format!("{}/n/{id}/extended", self.instance.base()))
- .send()
- .await?
- .error_for_status()?
- .json()
- .await?)
- }
-
- pub async fn node_asset(
- &self,
- writer: impl UnpinWrite,
- id: &str,
- role: AssetRole,
- width: usize,
- ) -> Result<()> {
- debug!("downloading asset {role:?} for {id:?}");
- self.download_url(
- writer,
- format!(
- "{}/n/{id}/asset?role={}&width={width}",
- self.instance.base(),
- role.as_str()
- ),
- )
- .await
- }
pub async fn node_thumbnail(
&self,
diff --git a/common/Cargo.toml b/common/Cargo.toml
index 1ee76c9..13fe29b 100644
--- a/common/Cargo.toml
+++ b/common/Cargo.toml
@@ -4,10 +4,10 @@ version = "0.1.0"
edition = "2021"
[dependencies]
-serde = { version = "1.0.214", features = ["derive"] }
+serde = { version = "1.0.217", features = ["derive"] }
bincode = { version = "2.0.0-rc.3", features = ["derive"] }
rocket = { workspace = true, optional = true }
-chrono = { version = "0.4.38", features = ["serde"] }
+chrono = { version = "0.4.39", features = ["serde"] }
[features]
rocket = ["dep:rocket"]
diff --git a/common/src/impl.rs b/common/src/impl.rs
index 25cc47d..a35216b 100644
--- a/common/src/impl.rs
+++ b/common/src/impl.rs
@@ -1,9 +1,10 @@
/*
This file is part of jellything (https://codeberg.org/metamuffin/jellything)
which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
- Copyright (C) 2024 metamuffin <metamuffin.org>
+ Copyright (C) 2025 metamuffin <metamuffin.org>
*/
-use crate::{AssetRole, SourceTrack, SourceTrackKind};
+use crate::{ObjectIds, PeopleGroup, SourceTrack, SourceTrackKind, TmdbKind, TraktKind};
+use std::{fmt::Display, str::FromStr};
impl SourceTrackKind {
pub fn letter(&self) -> char {
@@ -14,17 +15,7 @@ impl SourceTrackKind {
}
}
}
-
-impl AssetRole {
- pub fn as_str(&self) -> &'static str {
- match self {
- AssetRole::Poster => "poster",
- AssetRole::Backdrop => "backdrop",
- }
- }
-}
-
-impl std::fmt::Display for SourceTrack {
+impl Display for SourceTrack {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let kspec = match &self.kind {
SourceTrackKind::Video {
@@ -48,3 +39,110 @@ impl std::fmt::Display for SourceTrack {
))
}
}
+
+impl Display for TmdbKind {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_str(match self {
+ TmdbKind::Tv => "tv",
+ TmdbKind::Movie => "movie",
+ })
+ }
+}
+
+impl TraktKind {
+ pub fn singular(self) -> &'static str {
+ match self {
+ TraktKind::Movie => "movie",
+ TraktKind::Show => "show",
+ TraktKind::Season => "season",
+ TraktKind::Episode => "episode",
+ TraktKind::Person => "person",
+ TraktKind::User => "user",
+ }
+ }
+ pub fn plural(self) -> &'static str {
+ match self {
+ TraktKind::Movie => "movies",
+ TraktKind::Show => "shows",
+ TraktKind::Season => "seasons",
+ TraktKind::Episode => "episodes",
+ TraktKind::Person => "people",
+ TraktKind::User => "users", // //! not used in API
+ }
+ }
+}
+impl Display for TraktKind {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_str(match self {
+ TraktKind::Movie => "Movie",
+ TraktKind::Show => "Show",
+ TraktKind::Season => "Season",
+ TraktKind::Episode => "Episode",
+ TraktKind::Person => "Person",
+ TraktKind::User => "User",
+ })
+ }
+}
+impl Display for ObjectIds {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ if let Some(id) = self.trakt {
+ f.write_fmt(format_args!("trakt={}", id))?;
+ }
+ if let Some(_id) = &self.slug {
+ f.write_str(",slug")?;
+ }
+ if let Some(id) = self.tmdb {
+ f.write_fmt(format_args!(",tmdb={}", id))?;
+ }
+ if let Some(_id) = &self.imdb {
+ f.write_str(",imdb")?;
+ }
+ if let Some(_id) = &self.tvdb {
+ f.write_str(",tvdb")?;
+ }
+ if let Some(_id) = &self.omdb {
+ f.write_str(",omdb")?;
+ }
+ Ok(())
+ }
+}
+impl Display for PeopleGroup {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_str(match self {
+ PeopleGroup::Cast => "Cast",
+ PeopleGroup::Writing => "Writing",
+ PeopleGroup::Directing => "Directing",
+ PeopleGroup::Art => "Art",
+ PeopleGroup::Sound => "Sound",
+ PeopleGroup::Camera => "Camera",
+ PeopleGroup::Lighting => "Lighting",
+ PeopleGroup::Crew => "Crew",
+ PeopleGroup::Editing => "Editing",
+ PeopleGroup::Production => "Production",
+ PeopleGroup::Vfx => "Visual Effects",
+ PeopleGroup::CostumeMakeup => "Costume & Makeup",
+ PeopleGroup::CreatedBy => "Created by:",
+ })
+ }
+}
+impl FromStr for PeopleGroup {
+ type Err = ();
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ Ok(match s {
+ "Cast" => PeopleGroup::Cast,
+ "Writing" => PeopleGroup::Writing,
+ "Directing" => PeopleGroup::Directing,
+ "Art" => PeopleGroup::Art,
+ "Sound" => PeopleGroup::Sound,
+ "Camera" => PeopleGroup::Camera,
+ "Lighting" => PeopleGroup::Lighting,
+ "Crew" => PeopleGroup::Crew,
+ "Editing" => PeopleGroup::Editing,
+ "Production" => PeopleGroup::Production,
+ "Visual Effects" => PeopleGroup::Vfx,
+ "Costume & Makeup" => PeopleGroup::CostumeMakeup,
+ "Created by:" => PeopleGroup::CreatedBy,
+ _ => return Err(()),
+ })
+ }
+}
diff --git a/common/src/jhls.rs b/common/src/jhls.rs
index 12fa2d6..846e43a 100644
--- a/common/src/jhls.rs
+++ b/common/src/jhls.rs
@@ -1,9 +1,9 @@
-use bincode::{Decode, Encode};
/*
This file is part of jellything (https://codeberg.org/metamuffin/jellything)
which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
- Copyright (C) 2024 metamuffin <metamuffin.org>
+ Copyright (C) 2025 metamuffin <metamuffin.org>
*/
+use bincode::{Decode, Encode};
use serde::{Deserialize, Serialize};
use std::ops::Range;
diff --git a/common/src/lib.rs b/common/src/lib.rs
index 7403347..a72f345 100644
--- a/common/src/lib.rs
+++ b/common/src/lib.rs
@@ -1,9 +1,8 @@
/*
This file is part of jellything (https://codeberg.org/metamuffin/jellything)
which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
- Copyright (C) 2024 metamuffin <metamuffin.org>
+ Copyright (C) 2025 metamuffin <metamuffin.org>
*/
-#![allow(clippy::needless_borrows_for_generic_args)]
pub mod config;
pub mod helpers;
pub mod r#impl;
@@ -15,61 +14,34 @@ pub mod user;
pub use chrono;
use bincode::{Decode, Encode};
-#[cfg(feature = "rocket")]
-use rocket::{FromFormField, UriDisplayQuery};
use serde::{Deserialize, Serialize};
-use std::{collections::BTreeMap, fmt::Display, path::PathBuf};
+use std::{collections::BTreeMap, path::PathBuf};
#[derive(Debug, Clone, Deserialize, Serialize, Default, Encode, Decode)]
pub struct Node {
- #[serde(default)]
- pub public: NodePublic,
- #[serde(default)]
- pub private: NodePrivate,
-}
-
-#[rustfmt::skip]
-#[derive(Debug, Clone, Deserialize, Serialize, Default, Encode,Decode)]
-pub struct NodePrivate {
- #[serde(default)] pub id: Option<String>,
- #[serde(default)] pub source: Option<Vec<TrackSource>>,
-
- #[serde(default)] pub poster: Option<PathBuf>,
- #[serde(default)] pub backdrop: Option<PathBuf>,
-}
-
-#[rustfmt::skip]
-#[derive(Debug, Clone, Deserialize, Serialize, Default, Encode, Decode)]
-pub struct NodePublic {
- #[serde(default)] pub kind: Option<NodeKind>,
-
- #[serde(default)] pub poster: Option<Asset>,
- #[serde(default)] pub backdrop: Option<Asset>,
-
- #[serde(default)] pub title: Option<String>,
- #[serde(default)] pub subtitle: Option<String>,
- #[serde(default)] pub id: Option<String>,
- #[serde(default)] pub path: Vec<String>,
- #[serde(default)] pub tagline: Option<String>,
- #[serde(default)] pub children: Vec<String>,
- #[serde(default)] pub description: Option<String>,
- #[serde(default)] pub release_date: Option<i64>, // in unix millis
- #[serde(default)] pub index: Option<usize>,
- #[serde(default)] pub media: Option<MediaInfo>,
- #[serde(default)] pub ratings: BTreeMap<Rating, f64>,
- #[serde(default)] pub federated: Option<String>,
+ pub slug: String,
+ pub parents: Vec<String>,
+ pub kind: Option<NodeKind>,
+ pub poster: Option<Asset>,
+ pub backdrop: Option<Asset>,
+ pub title: Option<String>,
+ pub subtitle: Option<String>,
+ pub id: Option<String>,
+ pub tagline: Option<String>,
+ pub description: Option<String>,
+ pub release_date: Option<i64>, // in unix millis
+ pub index: Option<usize>,
+ pub media: Option<MediaInfo>,
+ pub ratings: BTreeMap<Rating, f64>,
+ pub federated: Option<String>,
+ pub people: BTreeMap<PeopleGroup, Vec<Appearance>>,
+ pub external_ids: ObjectIds,
}
-#[derive(Debug, Serialize, Deserialize, Encode, Decode, PartialEq, Eq, Clone)]
+#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Encode, Decode)]
pub struct Asset(pub String);
#[derive(Debug, Clone, Deserialize, Serialize, Default, Encode, Decode)]
-pub struct ExtendedNode {
- pub ids: ObjectIds,
- pub people: BTreeMap<PeopleGroup, Vec<Appearance>>,
-}
-
-#[derive(Debug, Clone, Deserialize, Serialize, Default, Encode, Decode)]
pub struct Appearance {
#[serde(default)]
pub jobs: Vec<String>,
@@ -95,75 +67,37 @@ pub struct ObjectIds {
pub tvdb: Option<u64>,
}
-#[rustfmt::skip]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Encode, Decode)]
-#[cfg_attr(feature = "rocket", derive(FromFormField, UriDisplayQuery))]
#[serde(rename_all = "snake_case")]
pub enum PeopleGroup {
- #[cfg_attr(feature = "rocket", field(value = "cast"))] Cast,
- #[cfg_attr(feature = "rocket", field(value = "writing"))] Writing,
- #[cfg_attr(feature = "rocket", field(value = "directing"))] Directing,
- #[cfg_attr(feature = "rocket", field(value = "art"))] Art,
- #[cfg_attr(feature = "rocket", field(value = "sound"))] Sound,
- #[cfg_attr(feature = "rocket", field(value = "camera"))] Camera,
- #[cfg_attr(feature = "rocket", field(value = "lighting"))] Lighting,
- #[cfg_attr(feature = "rocket", field(value = "crew"))] Crew,
- #[cfg_attr(feature = "rocket", field(value = "editing"))] Editing,
- #[cfg_attr(feature = "rocket", field(value = "production"))] Production,
- #[cfg_attr(feature = "rocket", field(value = "vfx"))] Vfx,
- #[cfg_attr(feature = "rocket", field(value = "costume"))] CostumeMakeup,
- #[cfg_attr(feature = "rocket", field(value = "createdby"))] CreatedBy,
-}
-
-#[derive(Debug, Clone, Deserialize, Serialize, Default, Encode, Decode)]
-pub struct ImportOptions {
- pub id: String,
- pub sources: Vec<ImportSource>,
-}
-
-#[derive(Debug, Clone, Deserialize, Serialize, Encode, Decode)]
-#[serde(rename_all = "snake_case")]
-pub enum ImportSource {
- Override(Node),
- Tmdb {
- kind: TmdbKind,
- id: u64,
- },
- Trakt {
- kind: TraktKind,
- id: u64,
- },
- AutoChildren {
- path: Option<PathBuf>,
- },
- Media {
- path: PathBuf,
- #[serde(default)]
- ignore_metadata: bool,
- #[serde(default)]
- ignore_attachments: bool,
- #[serde(default)]
- ignore_chapters: bool,
- },
- Federated {
- host: String,
- },
+ Cast,
+ Writing,
+ Directing,
+ Art,
+ Sound,
+ Camera,
+ Lighting,
+ Crew,
+ Editing,
+ Production,
+ Vfx,
+ CostumeMakeup,
+ CreatedBy,
}
-#[rustfmt::skip]
-#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, Default, Encode,Decode)]
-#[cfg_attr(feature = "rocket", derive(FromFormField, UriDisplayQuery))]
+#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, Default, Encode, Decode)]
#[serde(rename_all = "snake_case")]
pub enum NodeKind {
- #[cfg_attr(feature = "rocket", field(value = "movie"))] #[default] Movie,
- #[cfg_attr(feature = "rocket", field(value = "video"))] Video,
- #[cfg_attr(feature = "rocket", field(value = "shortformvideo"))] ShortFormVideo,
- #[cfg_attr(feature = "rocket", field(value = "collection"))] Collection,
- #[cfg_attr(feature = "rocket", field(value = "channel"))] Channel,
- #[cfg_attr(feature = "rocket", field(value = "show"))] Show,
- #[cfg_attr(feature = "rocket", field(value = "series"))] Series,
- #[cfg_attr(feature = "rocket", field(value = "season"))] Season,
- #[cfg_attr(feature = "rocket", field(value = "episode"))] Episode,
+ #[default]
+ Movie,
+ Video,
+ ShortFormVideo,
+ Collection,
+ Channel,
+ Show,
+ Series,
+ Season,
+ Episode,
}
#[derive(Debug, Clone, Deserialize, Serialize, Encode, Decode)]
@@ -175,7 +109,7 @@ pub enum TrackSource {
pub type TrackID = usize;
-#[derive(Debug, Clone, Deserialize, Serialize, Encode, Decode, Hash)]
+#[derive(Debug, Clone, Deserialize, Serialize, Hash, Encode, Decode)]
pub struct LocalTrack {
pub path: PathBuf,
pub track: TrackID,
@@ -199,6 +133,7 @@ pub struct Chapter {
#[derive(Debug, Clone, Deserialize, Serialize, Encode, Decode)]
pub struct SourceTrack {
+ pub source: TrackSource,
pub kind: SourceTrackKind,
pub name: String,
pub codec: String,
@@ -242,14 +177,6 @@ pub enum SourceTrackKind {
Subtitles,
}
-#[rustfmt::skip]
-#[derive(Debug, Clone, Copy, Encode, Decode)]
-#[cfg_attr(feature = "rocket", derive(FromFormField, UriDisplayQuery))]
-pub enum AssetRole {
- #[cfg_attr(feature = "rocket", field(value = "poster"))] Poster,
- #[cfg_attr(feature = "rocket", field(value = "backdrop"))] Backdrop,
-}
-
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Encode, Decode)]
#[serde(rename_all = "snake_case")]
pub enum TraktKind {
@@ -261,93 +188,8 @@ pub enum TraktKind {
User,
}
-impl TraktKind {
- pub fn singular(self) -> &'static str {
- match self {
- TraktKind::Movie => "movie",
- TraktKind::Show => "show",
- TraktKind::Season => "season",
- TraktKind::Episode => "episode",
- TraktKind::Person => "person",
- TraktKind::User => "user",
- }
- }
- pub fn plural(self) -> &'static str {
- match self {
- TraktKind::Movie => "movies",
- TraktKind::Show => "shows",
- TraktKind::Season => "seasons",
- TraktKind::Episode => "episodes",
- TraktKind::Person => "people",
- TraktKind::User => "users", // //! not used in API
- }
- }
-}
-impl Display for TraktKind {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.write_str(match self {
- TraktKind::Movie => "Movie",
- TraktKind::Show => "Show",
- TraktKind::Season => "Season",
- TraktKind::Episode => "Episode",
- TraktKind::Person => "Person",
- TraktKind::User => "User",
- })
- }
-}
-impl Display for ObjectIds {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- if let Some(id) = self.trakt {
- f.write_fmt(format_args!("trakt={}", id))?;
- }
- if let Some(_id) = &self.slug {
- f.write_str(",slug")?;
- }
- if let Some(id) = self.tmdb {
- f.write_fmt(format_args!(",tmdb={}", id))?;
- }
- if let Some(_id) = &self.imdb {
- f.write_str(",imdb")?;
- }
- if let Some(_id) = &self.tvdb {
- f.write_str(",tvdb")?;
- }
- if let Some(_id) = &self.omdb {
- f.write_str(",omdb")?;
- }
- Ok(())
- }
-}
-impl Display for PeopleGroup {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.write_str(match self {
- PeopleGroup::Cast => "Cast",
- PeopleGroup::Writing => "Writing",
- PeopleGroup::Directing => "Directing",
- PeopleGroup::Art => "Art",
- PeopleGroup::Sound => "Sound",
- PeopleGroup::Camera => "Camera",
- PeopleGroup::Lighting => "Lighting",
- PeopleGroup::Crew => "Crew",
- PeopleGroup::Editing => "Editing",
- PeopleGroup::Production => "Production",
- PeopleGroup::Vfx => "Visual Effects",
- PeopleGroup::CostumeMakeup => "Costume & Makeup",
- PeopleGroup::CreatedBy => "Created by:",
- })
- }
-}
-
-#[derive(Debug, Clone, Copy, Serialize, Deserialize, Encode, Decode)]
+#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum TmdbKind {
Tv,
Movie,
}
-impl Display for TmdbKind {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.write_str(match self {
- TmdbKind::Tv => "tv",
- TmdbKind::Movie => "movie",
- })
- }
-}
diff --git a/ebml_derive/Cargo.toml b/ebml_derive/Cargo.toml
index c33bcec..785360f 100644
--- a/ebml_derive/Cargo.toml
+++ b/ebml_derive/Cargo.toml
@@ -7,6 +7,6 @@ edition = "2021"
proc-macro = true
[dependencies]
-syn = "2.0.86"
-quote = "1.0.37"
+syn = "2.0.96"
+quote = "1.0.38"
diff --git a/import/Cargo.toml b/import/Cargo.toml
index 27872b7..e218cb0 100644
--- a/import/Cargo.toml
+++ b/import/Cargo.toml
@@ -11,13 +11,13 @@ jellymatroska = { path = "../matroska" }
jellyremuxer = { path = "../remuxer" }
log = { workspace = true }
-anyhow = "1.0.92"
+anyhow = "1.0.95"
reqwest = { workspace = true }
urlencoding = "2.1.3"
bincode = { version = "2.0.0-rc.3", features = ["derive"] }
-serde = { version = "1.0.214", features = ["derive"] }
-serde_json = "1.0.132"
+serde = { version = "1.0.217", features = ["derive"] }
+serde_json = "1.0.138"
serde_yaml = "0.9.34"
async-recursion = "1.1.1"
diff --git a/import/src/db.rs b/import/src/db.rs
deleted file mode 100644
index 7a3636c..0000000
--- a/import/src/db.rs
+++ /dev/null
@@ -1,208 +0,0 @@
-use anyhow::{anyhow, Context};
-use jellybase::database::{
- redb::{ReadableTable, ReadableTableMetadata},
- tantivy::{doc, DateTime},
- DataAcid, Ser, T_NODE, T_NODE_EXTENDED, T_NODE_IMPORT,
-};
-use jellycommon::{ExtendedNode, Node};
-use log::info;
-use std::collections::HashMap;
-use std::sync::RwLock;
-
-pub(crate) trait ImportStorage: Sync {
- fn add_partial_node(&self, id: &str, index_path: &[usize], node: Node) -> anyhow::Result<()>;
- fn add_partial_node_ext(
- &self,
- id: &str,
- index_path: &[usize],
- node: ExtendedNode,
- ) -> anyhow::Result<()>;
-
- fn get_partial_parts(&self, id: &str) -> anyhow::Result<Vec<(Vec<usize>, Node)>>;
- fn insert_complete_node(&self, id: &str, node: Node) -> anyhow::Result<()>;
-
- fn pre_clean(&self) -> anyhow::Result<()>;
- fn remove_prev_nodes(&self) -> anyhow::Result<()>;
- fn finish(&self) -> anyhow::Result<()>;
-}
-
-pub(crate) struct DatabaseStorage<'a> {
- pub db: &'a DataAcid,
-}
-impl<'a> DatabaseStorage<'a> {
- pub fn new(db: &'a DataAcid) -> Self {
- Self { db }
- }
-}
-impl ImportStorage for DatabaseStorage<'_> {
- fn pre_clean(&self) -> anyhow::Result<()> {
- let txn = self.db.begin_write()?;
- let mut table = txn.open_table(T_NODE_IMPORT)?;
- if !table.is_empty()? {
- info!("clearing temporary node tree from an aborted last import...");
- table.retain(|_, _| false)?;
- }
- drop(table);
- txn.commit()?;
- Ok(())
- }
- fn remove_prev_nodes(&self) -> anyhow::Result<()> {
- info!("removing old nodes...");
- let txn = self.db.inner.begin_write()?;
- let mut table = txn.open_table(T_NODE)?;
- table.retain(|_, _| false)?;
- drop(table);
- txn.commit()?;
- Ok(())
- }
- fn get_partial_parts(&self, id: &str) -> anyhow::Result<Vec<(Vec<usize>, Node)>> {
- let txn = self.db.inner.begin_read()?;
- let table = txn.open_table(T_NODE_IMPORT)?;
- let value = table.get(id)?.ok_or(anyhow!("node parts not found"))?;
- Ok(value.value().0)
- }
- fn insert_complete_node(&self, id: &str, node: Node) -> anyhow::Result<()> {
- insert_complete_node(self.db, id, node)
- }
-
- fn add_partial_node(&self, id: &str, index_path: &[usize], node: Node) -> anyhow::Result<()> {
- let txn = self.db.inner.begin_write()?;
- let mut table = txn.open_table(T_NODE_IMPORT)?;
-
- let mut parts = table.get(id)?.map(|a| a.value().0).unwrap_or_default();
- parts.push((index_path.to_vec(), node.clone()));
- table.insert(id, Ser(parts))?;
-
- drop(table);
- txn.commit()?;
- Ok(())
- }
-
- fn add_partial_node_ext(
- &self,
- id: &str,
- _index_path: &[usize],
- node: ExtendedNode,
- ) -> anyhow::Result<()> {
- // TODO merge this
- let txn = self.db.inner.begin_write()?;
- let mut table = txn.open_table(T_NODE_EXTENDED)?;
- table.insert(id, Ser(node))?;
- drop(table);
- txn.commit()?;
- Ok(())
- }
-
- fn finish(&self) -> anyhow::Result<()> {
- info!("clearing temporary node tree...");
- let txn = self.db.inner.begin_write()?;
- let mut table = txn.open_table(T_NODE_IMPORT)?;
- table.retain(|_, _| false)?;
- drop(table);
- txn.commit()?;
-
- self.db.node_index.writer.write().unwrap().commit()?;
- Ok(())
- }
-}
-
-pub type Parts = RwLock<HashMap<String, Vec<(Vec<usize>, Node)>>>;
-pub(crate) struct MemoryStorage<'a> {
- pub db: &'a DataAcid,
- pub parts: Parts,
-}
-impl<'a> MemoryStorage<'a> {
- pub fn new(db: &'a DataAcid) -> Self {
- Self {
- db,
- parts: Default::default(),
- }
- }
-}
-impl ImportStorage for MemoryStorage<'_> {
- fn pre_clean(&self) -> anyhow::Result<()> {
- Ok(())
- }
- fn remove_prev_nodes(&self) -> anyhow::Result<()> {
- info!("removing old nodes...");
- let txn = self.db.inner.begin_write()?;
- let mut table = txn.open_table(T_NODE)?;
- table.retain(|_, _| false)?;
- drop(table);
- txn.commit()?;
- self.db
- .node_index
- .writer
- .read()
- .unwrap()
- .delete_all_documents()?;
- self.db.node_index.writer.write().unwrap().commit()?;
- Ok(())
- }
- fn get_partial_parts(&self, id: &str) -> anyhow::Result<Vec<(Vec<usize>, Node)>> {
- Ok(self
- .parts
- .read()
- .unwrap()
- .get(id)
- .ok_or(anyhow!("node parts not found"))?
- .to_owned())
- }
- fn insert_complete_node(&self, id: &str, node: Node) -> anyhow::Result<()> {
- insert_complete_node(self.db, id, node)
- }
-
- fn add_partial_node(&self, id: &str, index_path: &[usize], node: Node) -> anyhow::Result<()> {
- self.parts
- .write()
- .unwrap()
- .entry(id.to_owned())
- .or_default()
- .push((index_path.to_owned(), node));
- Ok(())
- }
-
- fn add_partial_node_ext(
- &self,
- id: &str,
- _index_path: &[usize],
- node: ExtendedNode,
- ) -> anyhow::Result<()> {
- // TODO merge this
- let txn = self.db.inner.begin_write()?;
- let mut table = txn.open_table(T_NODE_EXTENDED)?;
- table.insert(id, Ser(node))?;
- drop(table);
- txn.commit()?;
- Ok(())
- }
-
- fn finish(&self) -> anyhow::Result<()> {
- self.db.node_index.writer.write().unwrap().commit()?;
- Ok(())
- }
-}
-
-fn insert_complete_node(db: &DataAcid, id: &str, node: Node) -> anyhow::Result<()> {
- let txn_write = db.inner.begin_write()?;
- let mut t_node = txn_write.open_table(T_NODE)?;
- t_node.insert(id, Ser(node.clone()))?;
- drop(t_node);
- txn_write.commit()?;
-
- db
- .node_index
- .writer
- .read()
- .unwrap()
- .add_document(doc!(
- db.node_index.id => node.public.id.unwrap_or_default(),
- db.node_index.title => node.public.title.unwrap_or_default(),
- db.node_index.description => node.public.description.unwrap_or_default(),
- db.node_index.releasedate => DateTime::from_timestamp_millis(node.public.release_date.unwrap_or_default()),
- db.node_index.f_index => node.public.index.unwrap_or_default() as u64,
- db.node_index.parent => node.public.path.last().cloned().unwrap_or_default(),
- ))
- .context("inserting document")?;
- Ok(())
-}
diff --git a/import/src/lib.rs b/import/src/lib.rs
index 89088e9..df23f7e 100644
--- a/import/src/lib.rs
+++ b/import/src/lib.rs
@@ -3,840 +3,839 @@
which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
Copyright (C) 2024 metamuffin <metamuffin.org>
*/
-pub mod db;
pub mod infojson;
pub mod tmdb;
pub mod trakt;
-use anyhow::{anyhow, bail, Context, Error, Ok};
-use async_recursion::async_recursion;
-use base64::Engine;
-use db::{DatabaseStorage, ImportStorage, MemoryStorage};
-use futures::{stream::FuturesUnordered, StreamExt};
-use jellybase::{
- assetfed::AssetInner,
- cache::{async_cache_file, cache_memory},
- database::DataAcid,
- federation::Federation,
- CONF, SECRETS,
-};
-use jellyclient::Session;
-use jellycommon::{
- chrono::{DateTime, Datelike},
- Asset, ExtendedNode, ImportOptions, ImportSource, MediaInfo, Node, NodeKind, NodePrivate,
- NodePublic, PeopleGroup, Rating, SourceTrack, TmdbKind, TrackSource, TraktKind,
-};
-use jellymatroska::read::EbmlReader;
-use jellyremuxer::metadata::import_metadata;
-use log::{debug, info, warn};
-use regex::Regex;
-use std::{
- cmp::Ordering,
- collections::HashSet,
- ffi::OsStr,
- fs::File,
- hash::RandomState,
- io::BufReader,
- ops::Deref,
- path::{Path, PathBuf},
- sync::{Arc, LazyLock},
-};
-use tmdb::{parse_release_date, Tmdb};
-use tokio::{
- io::AsyncWriteExt,
- sync::{RwLock, Semaphore},
- task::spawn_blocking,
-};
-use trakt::Trakt;
+// use anyhow::{anyhow, bail, Context, Error, Ok};
+// use async_recursion::async_recursion;
+// use base64::Engine;
+// use db::{DatabaseStorage, ImportStorage, MemoryStorage};
+// use futures::{stream::FuturesUnordered, StreamExt};
+// use jellybase::{
+// assetfed::AssetInner,
+// cache::{async_cache_file, cache_memory},
+// database::DataAcid,
+// federation::Federation,
+// CONF, SECRETS,
+// };
+// use jellyclient::Session;
+// use jellycommon::{
+// chrono::{DateTime, Datelike},
+// Asset, ExtendedNode, ImportOptions, ImportSource, MediaInfo, Node, NodeKind, NodePrivate,
+// NodePublic, PeopleGroup, Rating, SourceTrack, TmdbKind, TrackSource, TraktKind,
+// };
+// use jellymatroska::read::EbmlReader;
+// use jellyremuxer::metadata::import_metadata;
+// use log::{debug, info, warn};
+// use regex::Regex;
+// use std::{
+// cmp::Ordering,
+// collections::HashSet,
+// ffi::OsStr,
+// fs::File,
+// hash::RandomState,
+// io::BufReader,
+// ops::Deref,
+// path::{Path, PathBuf},
+// sync::{Arc, LazyLock},
+// };
+// use tmdb::{parse_release_date, Tmdb};
+// use tokio::{
+// io::AsyncWriteExt,
+// sync::{RwLock, Semaphore},
+// task::spawn_blocking,
+// };
+// use trakt::Trakt;
-static IMPORT_SEM: LazyLock<Semaphore> = LazyLock::new(|| Semaphore::new(1));
-pub static IMPORT_ERRORS: RwLock<Vec<String>> = RwLock::const_new(Vec::new());
+// static IMPORT_SEM: LazyLock<Semaphore> = LazyLock::new(|| Semaphore::new(1));
+// pub static IMPORT_ERRORS: RwLock<Vec<String>> = RwLock::const_new(Vec::new());
-static RE_EPISODE_FILENAME: LazyLock<Regex> =
- LazyLock::new(|| Regex::new(r#"([sS](\d+))?([eE](\d+))( (.+))?"#).unwrap());
-static RE_YOUTUBE_ID: LazyLock<Regex> =
- LazyLock::new(|| Regex::new(r#"\[([A-Za-z0-9_-]{11})\]"#).unwrap());
+// static RE_EPISODE_FILENAME: LazyLock<Regex> =
+// LazyLock::new(|| Regex::new(r#"([sS](\d+))?([eE](\d+))( (.+))?"#).unwrap());
+// static RE_YOUTUBE_ID: LazyLock<Regex> =
+// LazyLock::new(|| Regex::new(r#"\[([A-Za-z0-9_-]{11})\]"#).unwrap());
-struct Apis {
- trakt: Option<Trakt>,
- tmdb: Option<Tmdb>,
-}
+// struct Apis {
+// trakt: Option<Trakt>,
+// tmdb: Option<Tmdb>,
+// }
-pub fn is_importing() -> bool {
- IMPORT_SEM.available_permits() == 0
-}
+// pub fn is_importing() -> bool {
+// IMPORT_SEM.available_permits() == 0
+// }
-pub async fn import(db: &DataAcid, fed: &Federation) -> anyhow::Result<()> {
- let permit = IMPORT_SEM.try_acquire()?;
+// pub async fn import(db: &DataAcid, fed: &Federation) -> anyhow::Result<()> {
+// let permit = IMPORT_SEM.try_acquire()?;
- let ap = Apis {
- trakt: SECRETS.api.trakt.as_ref().map(|key| Trakt::new(key)),
- tmdb: SECRETS.api.tmdb.as_ref().map(|key| Tmdb::new(key)),
- };
+// let ap = Apis {
+// trakt: SECRETS.api.trakt.as_ref().map(|key| Trakt::new(key)),
+// tmdb: SECRETS.api.tmdb.as_ref().map(|key| Tmdb::new(key)),
+// };
- let e = if CONF.use_in_memory_import_storage {
- import_inner(&MemoryStorage::new(db), fed, &ap).await
- } else {
- import_inner(&DatabaseStorage::new(db), fed, &ap).await
- };
- let e = match e {
- Result::Ok(e) => e,
- Result::Err(e) => vec![e],
- };
- *IMPORT_ERRORS.write().await = e.into_iter().map(|e| format!("{e:?}")).collect();
+// let e = if CONF.use_in_memory_import_storage {
+// import_inner(&MemoryStorage::new(db), fed, &ap).await
+// } else {
+// import_inner(&DatabaseStorage::new(db), fed, &ap).await
+// };
+// let e = match e {
+// Result::Ok(e) => e,
+// Result::Err(e) => vec![e],
+// };
+// *IMPORT_ERRORS.write().await = e.into_iter().map(|e| format!("{e:?}")).collect();
- drop(permit);
- Ok(())
-}
+// drop(permit);
+// Ok(())
+// }
-pub(crate) async fn import_inner(
- db: &impl ImportStorage,
- fed: &Federation,
- ap: &Apis,
-) -> anyhow::Result<Vec<anyhow::Error>> {
- db.pre_clean()?;
- info!("loading sources...");
- let mut errors = Vec::new();
- match import_path(CONF.library_path.clone(), vec![], db, fed, ap)
- .await
- .context("indexing")
- {
- Result::Ok(o) => errors.extend(o),
- Result::Err(e) => errors.push(e),
- };
- db.remove_prev_nodes()?;
- info!("merging nodes...");
- match generate_node_paths(db).context("merging nodes") {
- Result::Ok(o) => errors.extend(o),
- Result::Err(e) => errors.push(e),
- }
- db.finish()?;
- info!("import completed");
- Ok(errors)
-}
+// pub(crate) async fn import_inner(
+// db: &impl ImportStorage,
+// fed: &Federation,
+// ap: &Apis,
+// ) -> anyhow::Result<Vec<anyhow::Error>> {
+// db.pre_clean()?;
+// info!("loading sources...");
+// let mut errors = Vec::new();
+// match import_path(CONF.library_path.clone(), vec![], db, fed, ap)
+// .await
+// .context("indexing")
+// {
+// Result::Ok(o) => errors.extend(o),
+// Result::Err(e) => errors.push(e),
+// };
+// db.remove_prev_nodes()?;
+// info!("merging nodes...");
+// match generate_node_paths(db).context("merging nodes") {
+// Result::Ok(o) => errors.extend(o),
+// Result::Err(e) => errors.push(e),
+// }
+// db.finish()?;
+// info!("import completed");
+// Ok(errors)
+// }
-fn generate_node_paths(db: &impl ImportStorage) -> anyhow::Result<Vec<Error>> {
- // TODO mark nodes done to allow recursion
- fn traverse(
- db: &impl ImportStorage,
- id: String,
- mut path: Vec<String>,
- parent_title: &str,
- ) -> anyhow::Result<Vec<Error>> {
- let mut errors = Vec::new();
- let node = {
- let mut parts = db
- .get_partial_parts(&id)
- .context(anyhow!("path = {path:?}"))?;
+// fn generate_node_paths(db: &impl ImportStorage) -> anyhow::Result<Vec<Error>> {
+// // TODO mark nodes done to allow recursion
+// fn traverse(
+// db: &impl ImportStorage,
+// id: String,
+// mut path: Vec<String>,
+// parent_title: &str,
+// ) -> anyhow::Result<Vec<Error>> {
+// let mut errors = Vec::new();
+// let node = {
+// let mut parts = db
+// .get_partial_parts(&id)
+// .context(anyhow!("path = {path:?}"))?;
- parts.sort_by(|(x, _), (y, _)| compare_index_path(x, y));
+// parts.sort_by(|(x, _), (y, _)| compare_index_path(x, y));
- let mut node = parts
- .into_iter()
- .map(|(_, x)| x)
- .reduce(|x, y| merge_node(x, y).unwrap())
- .unwrap();
+// let mut node = parts
+// .into_iter()
+// .map(|(_, x)| x)
+// .reduce(|x, y| merge_node(x, y).unwrap())
+// .unwrap();
- node.public.id = Some(id.to_owned());
- node.public.path = vec![]; // will be reconstructed in the next pass
- node.public.federated = None;
+// node.public.id = Some(id.to_owned());
+// node.public.path = vec![]; // will be reconstructed in the next pass
+// node.public.federated = None;
- // TODO this discardes a lot of information. maybe change this.
- if let Some(media) = &node.public.media {
- for t in &media.tracks {
- if let Some(host) = t.federated.first() {
- if host != &CONF.hostname {
- node.public.federated = Some(host.to_string())
- }
- }
- }
- }
+// // TODO this discardes a lot of information. maybe change this.
+// if let Some(media) = &node.public.media {
+// for t in &media.tracks {
+// if let Some(host) = t.federated.first() {
+// if host != &CONF.hostname {
+// node.public.federated = Some(host.to_string())
+// }
+// }
+// }
+// }
- if node.public.path.is_empty() {
- node.public.path = path.clone();
- }
- node.public.subtitle = match node.public.kind.unwrap_or_default() {
- NodeKind::Movie => node.public.release_date.map(|date| {
- format!(
- "{}",
- DateTime::from_timestamp_millis(date)
- .unwrap()
- .date_naive()
- .year()
- )
- }),
- NodeKind::Season
- | NodeKind::Episode
- | NodeKind::ShortFormVideo
- | NodeKind::Video => Some(parent_title.to_string()),
- _ => None,
- };
+// if node.public.path.is_empty() {
+// node.public.path = path.clone();
+// }
+// node.public.subtitle = match node.public.kind.unwrap_or_default() {
+// NodeKind::Movie => node.public.release_date.map(|date| {
+// format!(
+// "{}",
+// DateTime::from_timestamp_millis(date)
+// .unwrap()
+// .date_naive()
+// .year()
+// )
+// }),
+// NodeKind::Season
+// | NodeKind::Episode
+// | NodeKind::ShortFormVideo
+// | NodeKind::Video => Some(parent_title.to_string()),
+// _ => None,
+// };
- db.insert_complete_node(&id, node.clone())?;
+// db.insert_complete_node(&id, node.clone())?;
- node
- };
+// node
+// };
- path.push(id);
- let ps = node.public.title.unwrap_or_default();
- for c in node.public.children {
- match traverse(db, c, path.clone(), &ps) {
- Result::Ok(o) => errors.extend(o),
- Result::Err(e) => errors.push(e),
- }
- }
- Ok(errors)
- }
- traverse(db, "library".to_string(), vec![], "Root")
-}
+// path.push(id);
+// let ps = node.public.title.unwrap_or_default();
+// for c in node.public.children {
+// match traverse(db, c, path.clone(), &ps) {
+// Result::Ok(o) => errors.extend(o),
+// Result::Err(e) => errors.push(e),
+// }
+// }
+// Ok(errors)
+// }
+// traverse(db, "library".to_string(), vec![], "Root")
+// }
-fn compare_index_path(x: &[usize], y: &[usize]) -> Ordering {
- if x.is_empty() {
- Ordering::Greater
- } else if y.is_empty() {
- Ordering::Less
- } else {
- match x[0].cmp(&y[0]) {
- o @ (Ordering::Less | Ordering::Greater) => o,
- Ordering::Equal => compare_index_path(&x[1..], &y[1..]),
- }
- }
-}
+// fn compare_index_path(x: &[usize], y: &[usize]) -> Ordering {
+// if x.is_empty() {
+// Ordering::Greater
+// } else if y.is_empty() {
+// Ordering::Less
+// } else {
+// match x[0].cmp(&y[0]) {
+// o @ (Ordering::Less | Ordering::Greater) => o,
+// Ordering::Equal => compare_index_path(&x[1..], &y[1..]),
+// }
+// }
+// }
-#[async_recursion]
-async fn import_path(
- path: PathBuf,
- mut index_path: Vec<usize>,
- db: &impl ImportStorage,
- fed: &Federation,
- ap: &Apis,
-) -> anyhow::Result<Vec<anyhow::Error>> {
- let mut errors = Vec::new();
- if path.is_dir() {
- let mut children_paths = path
- .read_dir()?
- .map(Result::unwrap)
- .filter_map(|e| {
- if e.path().extension() == Some(OsStr::new("yaml"))
- || e.path().extension() == Some(OsStr::new("jelly"))
- || e.metadata().unwrap().is_dir()
- {
- Some(e.path())
- } else {
- None
- }
- })
- .collect::<Vec<_>>();
+// #[async_recursion]
+// async fn import_path(
+// path: PathBuf,
+// mut index_path: Vec<usize>,
+// db: &impl ImportStorage,
+// fed: &Federation,
+// ap: &Apis,
+// ) -> anyhow::Result<Vec<anyhow::Error>> {
+// let mut errors = Vec::new();
+// if path.is_dir() {
+// let mut children_paths = path
+// .read_dir()?
+// .map(Result::unwrap)
+// .filter_map(|e| {
+// if e.path().extension() == Some(OsStr::new("yaml"))
+// || e.path().extension() == Some(OsStr::new("jelly"))
+// || e.metadata().unwrap().is_dir()
+// {
+// Some(e.path())
+// } else {
+// None
+// }
+// })
+// .collect::<Vec<_>>();
- children_paths.sort();
+// children_paths.sort();
- let mut children: FuturesUnordered<_> = children_paths
- .into_iter()
- .enumerate()
- .map(|(i, p)| {
- import_path(
- p.clone(),
- {
- let mut path = index_path.clone();
- path.push(i);
- path
- },
- db,
- fed,
- ap,
- )
- })
- .collect();
+// let mut children: FuturesUnordered<_> = children_paths
+// .into_iter()
+// .enumerate()
+// .map(|(i, p)| {
+// import_path(
+// p.clone(),
+// {
+// let mut path = index_path.clone();
+// path.push(i);
+// path
+// },
+// db,
+// fed,
+// ap,
+// )
+// })
+// .collect();
- while let Some(k) = children.next().await {
- match k {
- Result::Ok(o) => errors.extend(o),
- Result::Err(e) => errors.push(e),
- }
- }
- } else {
- info!("reading {path:?}");
- let opts = File::open(&path).context(anyhow!("opening {path:?}"))?;
- let opts: ImportOptions = if path.extension() == Some(OsStr::new("jelly")) {
- serde_json::from_reader(opts).context(anyhow!("parsing json {path:?}"))?
- } else {
- serde_yaml::from_reader(opts).context(anyhow!("parsing yaml {path:?}"))?
- };
+// while let Some(k) = children.next().await {
+// match k {
+// Result::Ok(o) => errors.extend(o),
+// Result::Err(e) => errors.push(e),
+// }
+// }
+// } else {
+// info!("reading {path:?}");
+// let opts = File::open(&path).context(anyhow!("opening {path:?}"))?;
+// let opts: ImportOptions = if path.extension() == Some(OsStr::new("jelly")) {
+// serde_json::from_reader(opts).context(anyhow!("parsing json {path:?}"))?
+// } else {
+// serde_yaml::from_reader(opts).context(anyhow!("parsing yaml {path:?}"))?
+// };
- for (i, s) in opts.sources.into_iter().enumerate() {
- index_path.push(i);
- if let Err(e) = process_source(opts.id.clone(), s, &path, &index_path, db, fed, ap)
- .await
- .context(anyhow!("processing source in {path:?}"))
- {
- errors.push(e)
- }
- index_path.pop();
- }
- }
- Ok(errors)
-}
+// for (i, s) in opts.sources.into_iter().enumerate() {
+// index_path.push(i);
+// if let Err(e) = process_source(opts.id.clone(), s, &path, &index_path, db, fed, ap)
+// .await
+// .context(anyhow!("processing source in {path:?}"))
+// {
+// errors.push(e)
+// }
+// index_path.pop();
+// }
+// }
+// Ok(errors)
+// }
-static SEM_IMPORT: Semaphore = Semaphore::const_new(2);
+// static SEM_IMPORT: Semaphore = Semaphore::const_new(2);
-#[async_recursion]
-async fn process_source(
- id: String,
- s: ImportSource,
- path: &Path,
- index_path: &[usize],
- db: &impl ImportStorage,
- fed: &Federation,
- ap: &Apis,
-) -> anyhow::Result<Vec<anyhow::Error>> {
- let mut errors = vec![];
- match s {
- ImportSource::Override(mut n) => {
- if let Some(backdrop) = n.private.backdrop.clone() {
- n.public.backdrop = Some(AssetInner::Library(backdrop).ser());
- }
- if let Some(poster) = n.private.poster.clone() {
- n.public.poster = Some(AssetInner::Library(poster).ser());
- }
- db.add_partial_node(&id, index_path, n)?
- }
- ImportSource::Trakt { id: tid, kind } => {
- info!("trakt {id}");
- let trakt = ap
- .trakt
- .as_ref()
- .ok_or(anyhow!("trakt api key is required"))?;
- let trakt_object = trakt
- .lookup(kind, tid, true)
- .await
- .context("looking up metadata")?;
- let trakt_people = trakt
- .people(kind, tid, true)
- .await
- .context("looking up people")?;
+// #[async_recursion]
+// async fn process_source(
+// id: String,
+// s: ImportSource,
+// path: &Path,
+// index_path: &[usize],
+// db: &impl ImportStorage,
+// fed: &Federation,
+// ap: &Apis,
+// ) -> anyhow::Result<Vec<anyhow::Error>> {
+// let mut errors = vec![];
+// match s {
+// ImportSource::Override(mut n) => {
+// if let Some(backdrop) = n.private.backdrop.clone() {
+// n.public.backdrop = Some(AssetInner::Library(backdrop).ser());
+// }
+// if let Some(poster) = n.private.poster.clone() {
+// n.public.poster = Some(AssetInner::Library(poster).ser());
+// }
+// db.add_partial_node(&id, index_path, n)?
+// }
+// ImportSource::Trakt { id: tid, kind } => {
+// info!("trakt {id}");
+// let trakt = ap
+// .trakt
+// .as_ref()
+// .ok_or(anyhow!("trakt api key is required"))?;
+// let trakt_object = trakt
+// .lookup(kind, tid, true)
+// .await
+// .context("looking up metadata")?;
+// let trakt_people = trakt
+// .people(kind, tid, true)
+// .await
+// .context("looking up people")?;
- let mut node = Node::default();
- let mut node_ext = ExtendedNode::default();
- {
- node.public.kind = Some(match kind {
- TraktKind::Movie => NodeKind::Movie,
- TraktKind::Show => NodeKind::Show,
- TraktKind::Season => NodeKind::Season,
- TraktKind::Episode => NodeKind::Episode,
- _ => bail!("unexpected kind for trakt import"),
- });
- node.public.title = Some(trakt_object.title.to_owned());
- if let Some(overview) = &trakt_object.overview {
- node.public.description = Some(overview.to_owned())
- }
- if let Some(tagline) = &trakt_object.tagline {
- node.public.tagline = Some(tagline.to_owned())
- }
- if let Some(rating) = &trakt_object.rating {
- node.public.ratings.insert(Rating::Trakt, *rating);
- }
- for p in trakt_people.cast.iter() {
- node_ext
- .people
- .entry(PeopleGroup::Cast)
- .or_default()
- .push(p.a())
- }
- for (group, people) in trakt_people.crew.iter() {
- for p in people {
- node_ext.people.entry(group.a()).or_default().push(p.a())
- }
- }
- // TODO lazy assets
- for ps in node_ext.people.values_mut() {
- for p in ps {
- if let Some(id) = p.person.ids.tmdb {
- if let Some(tmdb) = &ap.tmdb {
- let k = tmdb.person_image(id).await?;
- if let Some(prof) = k.profiles.first() {
- p.person.headshot = Some(
- AssetInner::Cache(tmdb.image(&prof.file_path).await?).ser(),
- );
- }
- }
- }
- }
- }
- }
- db.add_partial_node(&id, index_path, node)?;
- db.add_partial_node_ext(&id, index_path, node_ext)?;
+// let mut node = Node::default();
+// let mut node_ext = ExtendedNode::default();
+// {
+// node.public.kind = Some(match kind {
+// TraktKind::Movie => NodeKind::Movie,
+// TraktKind::Show => NodeKind::Show,
+// TraktKind::Season => NodeKind::Season,
+// TraktKind::Episode => NodeKind::Episode,
+// _ => bail!("unexpected kind for trakt import"),
+// });
+// node.public.title = Some(trakt_object.title.to_owned());
+// if let Some(overview) = &trakt_object.overview {
+// node.public.description = Some(overview.to_owned())
+// }
+// if let Some(tagline) = &trakt_object.tagline {
+// node.public.tagline = Some(tagline.to_owned())
+// }
+// if let Some(rating) = &trakt_object.rating {
+// node.public.ratings.insert(Rating::Trakt, *rating);
+// }
+// for p in trakt_people.cast.iter() {
+// node_ext
+// .people
+// .entry(PeopleGroup::Cast)
+// .or_default()
+// .push(p.a())
+// }
+// for (group, people) in trakt_people.crew.iter() {
+// for p in people {
+// node_ext.people.entry(group.a()).or_default().push(p.a())
+// }
+// }
+// // TODO lazy assets
+// for ps in node_ext.people.values_mut() {
+// for p in ps {
+// if let Some(id) = p.person.ids.tmdb {
+// if let Some(tmdb) = &ap.tmdb {
+// let k = tmdb.person_image(id).await?;
+// if let Some(prof) = k.profiles.first() {
+// p.person.headshot = Some(
+// AssetInner::Cache(tmdb.image(&prof.file_path).await?).ser(),
+// );
+// }
+// }
+// }
+// }
+// }
+// }
+// db.add_partial_node(&id, index_path, node)?;
+// db.add_partial_node_ext(&id, index_path, node_ext)?;
- if let Some(tid) = trakt_object.ids.tmdb {
- if let Some(kind) = match kind {
- TraktKind::Movie => Some(TmdbKind::Movie),
- TraktKind::Show => Some(TmdbKind::Tv),
- TraktKind::Season => Some(TmdbKind::Tv), // TODO
- TraktKind::Episode | TraktKind::Person | TraktKind::User => None,
- } {
- let mut index_path = index_path.to_vec();
- index_path.push(1);
- match process_source(
- id,
- ImportSource::Tmdb { id: tid, kind },
- path,
- &index_path,
- db,
- fed,
- ap,
- )
- .await
- {
- Result::Ok(o) => errors.extend(o),
- Result::Err(e) => errors.push(e),
- }
- }
- }
- }
- ImportSource::Tmdb { id: tid, kind } => {
- info!("tmdb {id}");
- let tmdb = ap
- .tmdb
- .as_ref()
- .ok_or(anyhow!("tmdb api key is required"))?;
+// if let Some(tid) = trakt_object.ids.tmdb {
+// if let Some(kind) = match kind {
+// TraktKind::Movie => Some(TmdbKind::Movie),
+// TraktKind::Show => Some(TmdbKind::Tv),
+// TraktKind::Season => Some(TmdbKind::Tv), // TODO
+// TraktKind::Episode | TraktKind::Person | TraktKind::User => None,
+// } {
+// let mut index_path = index_path.to_vec();
+// index_path.push(1);
+// match process_source(
+// id,
+// ImportSource::Tmdb { id: tid, kind },
+// path,
+// &index_path,
+// db,
+// fed,
+// ap,
+// )
+// .await
+// {
+// Result::Ok(o) => errors.extend(o),
+// Result::Err(e) => errors.push(e),
+// }
+// }
+// }
+// }
+// ImportSource::Tmdb { id: tid, kind } => {
+// info!("tmdb {id}");
+// let tmdb = ap
+// .tmdb
+// .as_ref()
+// .ok_or(anyhow!("tmdb api key is required"))?;
- let details = tmdb.details(kind, tid).await?;
+// let details = tmdb.details(kind, tid).await?;
- let mut node = Node::default();
+// let mut node = Node::default();
- // TODO lazy assets
- if let Some(poster) = &details.poster_path {
- node.public.poster = Some(AssetInner::Cache(tmdb.image(poster).await?).ser());
- }
- if let Some(backdrop) = &details.backdrop_path {
- node.public.backdrop = Some(AssetInner::Cache(tmdb.image(backdrop).await?).ser());
- }
+// // TODO lazy assets
+// if let Some(poster) = &details.poster_path {
+// node.public.poster = Some(AssetInner::Cache(tmdb.image(poster).await?).ser());
+// }
+// if let Some(backdrop) = &details.backdrop_path {
+// node.public.backdrop = Some(AssetInner::Cache(tmdb.image(backdrop).await?).ser());
+// }
- node.public.tagline = details.tagline.clone();
- node.public.title = details.title.clone();
- node.public.description = Some(details.overview.clone());
- node.public
- .ratings
- .insert(Rating::Tmdb, details.vote_average);
- if let Some(date) = details.release_date.clone() {
- node.public.release_date =
- parse_release_date(&date).context("parsing release date")?;
- }
+// node.public.tagline = details.tagline.clone();
+// node.public.title = details.title.clone();
+// node.public.description = Some(details.overview.clone());
+// node.public
+// .ratings
+// .insert(Rating::Tmdb, details.vote_average);
+// if let Some(date) = details.release_date.clone() {
+// node.public.release_date =
+// parse_release_date(&date).context("parsing release date")?;
+// }
- db.add_partial_node(&id, index_path, node)?;
- }
- ImportSource::Media {
- path: mpath,
- ignore_attachments,
- ignore_chapters,
- ignore_metadata,
- } => {
- info!("media import {mpath:?}");
- let abspath = CONF.media_path.join(&mpath);
- if !abspath.exists() {
- bail!("media missing at {abspath:?}");
- }
- if abspath.is_dir() {
- let mut node = Node::default();
- for f in abspath.read_dir()? {
- let f = f?;
- let child_path = f.path();
- if child_path.is_dir()
- || matches!(
- child_path.extension().map(|o| o.to_str().unwrap()),
- Some("mks" | "mka" | "mkv" | "webm")
- )
- {
- let inf_id =
- infer_id_from_path(&child_path).context("inferring child id")?;
+// db.add_partial_node(&id, index_path, node)?;
+// }
+// ImportSource::Media {
+// path: mpath,
+// ignore_attachments,
+// ignore_chapters,
+// ignore_metadata,
+// } => {
+// info!("media import {mpath:?}");
+// let abspath = CONF.media_path.join(&mpath);
+// if !abspath.exists() {
+// bail!("media missing at {abspath:?}");
+// }
+// if abspath.is_dir() {
+// let mut node = Node::default();
+// for f in abspath.read_dir()? {
+// let f = f?;
+// let child_path = f.path();
+// if child_path.is_dir()
+// || matches!(
+// child_path.extension().map(|o| o.to_str().unwrap()),
+// Some("mks" | "mka" | "mkv" | "webm")
+// )
+// {
+// let inf_id =
+// infer_id_from_path(&child_path).context("inferring child id")?;
- match process_source(
- inf_id.clone(),
- ImportSource::Media {
- path: mpath.join(f.file_name()),
- ignore_attachments,
- ignore_chapters,
- ignore_metadata,
- },
- path,
- index_path,
- db,
- fed,
- ap,
- )
- .await
- .context(anyhow!("recursive media import: {:?}", f.path()))
- {
- Result::Ok(o) => errors.extend(o),
- Result::Err(e) => errors.push(e),
- };
- node.public.children.push(inf_id);
- }
- }
- db.add_partial_node(&id, index_path, node)?;
- } else if abspath.is_file() {
- let _permit = SEM_IMPORT.acquire().await.unwrap();
- let metadata = {
- let abspath = abspath.clone();
- let mpath = mpath.to_owned();
- spawn_blocking(move || {
- cache_memory(&["probe", mpath.to_str().unwrap()], || {
- let input = File::open(&abspath).context("opening media file")?;
- let mut input = EbmlReader::new(BufReader::new(input));
- import_metadata(&mut input)
- })
- })
- }
- .await?
- .context(anyhow!("probing {abspath:?}"))?
- .deref()
- .to_owned();
+// match process_source(
+// inf_id.clone(),
+// ImportSource::Media {
+// path: mpath.join(f.file_name()),
+// ignore_attachments,
+// ignore_chapters,
+// ignore_metadata,
+// },
+// path,
+// index_path,
+// db,
+// fed,
+// ap,
+// )
+// .await
+// .context(anyhow!("recursive media import: {:?}", f.path()))
+// {
+// Result::Ok(o) => errors.extend(o),
+// Result::Err(e) => errors.push(e),
+// };
+// node.public.children.push(inf_id);
+// }
+// }
+// db.add_partial_node(&id, index_path, node)?;
+// } else if abspath.is_file() {
+// let _permit = SEM_IMPORT.acquire().await.unwrap();
+// let metadata = {
+// let abspath = abspath.clone();
+// let mpath = mpath.to_owned();
+// spawn_blocking(move || {
+// cache_memory(&["probe", mpath.to_str().unwrap()], || {
+// let input = File::open(&abspath).context("opening media file")?;
+// let mut input = EbmlReader::new(BufReader::new(input));
+// import_metadata(&mut input)
+// })
+// })
+// }
+// .await?
+// .context(anyhow!("probing {abspath:?}"))?
+// .deref()
+// .to_owned();
- let mut node = Node::default();
+// let mut node = Node::default();
- if !ignore_metadata {
- if let Some(captures) =
- RE_EPISODE_FILENAME.captures(abspath.file_stem().unwrap().to_str().unwrap())
- {
- node.public.index = captures.get(4).and_then(|a| a.as_str().parse().ok());
- if let Some(title) = captures.get(6) {
- node.public.title = Some(title.as_str().to_string());
- }
- }
- node.public.title = metadata.title;
- node.public.description = metadata.description;
- node.public.tagline = metadata.tagline;
- }
- node.public.media = Some(MediaInfo {
- duration: metadata.duration,
- tracks: metadata.tracks,
- chapters: if ignore_chapters {
- vec![]
- } else {
- metadata.chapters
- },
- });
- node.private.source = Some(
- metadata
- .track_sources
- .into_iter()
- .map(|mut ts| {
- ts.path = mpath.to_owned();
- TrackSource::Local(ts)
- })
- .collect(),
- );
+// if !ignore_metadata {
+// if let Some(captures) =
+// RE_EPISODE_FILENAME.captures(abspath.file_stem().unwrap().to_str().unwrap())
+// {
+// node.public.index = captures.get(4).and_then(|a| a.as_str().parse().ok());
+// if let Some(title) = captures.get(6) {
+// node.public.title = Some(title.as_str().to_string());
+// }
+// }
+// node.public.title = metadata.title;
+// node.public.description = metadata.description;
+// node.public.tagline = metadata.tagline;
+// }
+// node.public.media = Some(MediaInfo {
+// duration: metadata.duration,
+// tracks: metadata.tracks,
+// chapters: if ignore_chapters {
+// vec![]
+// } else {
+// metadata.chapters
+// },
+// });
+// node.private.source = Some(
+// metadata
+// .track_sources
+// .into_iter()
+// .map(|mut ts| {
+// ts.path = mpath.to_owned();
+// TrackSource::Local(ts)
+// })
+// .collect(),
+// );
- if !ignore_attachments {
- if let Some((filename, data)) = metadata.cover {
- node.public.poster = Some(
- AssetInner::Cache(
- async_cache_file(
- &["att-cover", mpath.to_str().unwrap(), &filename],
- |mut f| async move {
- f.write_all(&data).await?;
- Ok(())
- },
- )
- .await?,
- )
- .ser(),
- )
- };
+// if !ignore_attachments {
+// if let Some((filename, data)) = metadata.cover {
+// node.public.poster = Some(
+// AssetInner::Cache(
+// async_cache_file(
+// &["att-cover", mpath.to_str().unwrap(), &filename],
+// |mut f| async move {
+// f.write_all(&data).await?;
+// Ok(())
+// },
+// )
+// .await?,
+// )
+// .ser(),
+// )
+// };
- if let Some(infojson) = metadata.infojson {
- let infojson: infojson::YVideo =
- serde_json::from_str(&infojson).context("parsing infojson")?;
+// if let Some(infojson) = metadata.infojson {
+// let infojson: infojson::YVideo =
+// serde_json::from_str(&infojson).context("parsing infojson")?;
- node.public.kind = Some(
- if infojson.duration.unwrap_or(0.) < 120.
- && infojson.aspect_ratio.unwrap_or(2.) < 1.
- {
- NodeKind::ShortFormVideo
- } else {
- NodeKind::Video
- },
- );
- node.public.title = Some(infojson.title);
- node.public.description = Some(infojson.description);
- node.public.tagline = Some(infojson.webpage_url);
- node.public
- .ratings
- .insert(Rating::YoutubeViews, infojson.view_count as f64);
- node.public.release_date = Some(
- infojson::parse_upload_date(&infojson.upload_date)
- .context("parsing upload date")?,
- );
- node.public.ratings.extend(
- infojson
- .like_count
- .map(|l| (Rating::YoutubeLikes, l as f64)),
- );
- }
- }
- drop(_permit);
- db.add_partial_node(&id, index_path, node)?;
- } else {
- warn!("non file/dir import ignored: {abspath:?}")
- }
- }
- ImportSource::Federated { host } => {
- info!("federated import of {id:?} from {host:?}");
- let session = fed.get_session(&host).await.context("creating session")?;
+// node.public.kind = Some(
+// if infojson.duration.unwrap_or(0.) < 120.
+// && infojson.aspect_ratio.unwrap_or(2.) < 1.
+// {
+// NodeKind::ShortFormVideo
+// } else {
+// NodeKind::Video
+// },
+// );
+// node.public.title = Some(infojson.title);
+// node.public.description = Some(infojson.description);
+// node.public.tagline = Some(infojson.webpage_url);
+// node.public
+// .ratings
+// .insert(Rating::YoutubeViews, infojson.view_count as f64);
+// node.public.release_date = Some(
+// infojson::parse_upload_date(&infojson.upload_date)
+// .context("parsing upload date")?,
+// );
+// node.public.ratings.extend(
+// infojson
+// .like_count
+// .map(|l| (Rating::YoutubeLikes, l as f64)),
+// );
+// }
+// }
+// drop(_permit);
+// db.add_partial_node(&id, index_path, node)?;
+// } else {
+// warn!("non file/dir import ignored: {abspath:?}")
+// }
+// }
+// ImportSource::Federated { host } => {
+// info!("federated import of {id:?} from {host:?}");
+// let session = fed.get_session(&host).await.context("creating session")?;
- import_remote(id.clone(), &host, db, &session, index_path)
- .await
- .context("federated import")?
- }
- ImportSource::AutoChildren { path: cpath } => {
- info!("auto children at {path:?}");
- let paths = cpath
- .unwrap_or_else(|| path.parent().unwrap().to_path_buf())
- .read_dir()?
- .map(Result::unwrap)
- .map(|e| e.path())
- .filter(|e| {
- e.extension() == Some(OsStr::new("yaml"))
- || e.extension() == Some(OsStr::new("jelly"))
- });
+// import_remote(id.clone(), &host, db, &session, index_path)
+// .await
+// .context("federated import")?
+// }
+// ImportSource::AutoChildren { path: cpath } => {
+// info!("auto children at {path:?}");
+// let paths = cpath
+// .unwrap_or_else(|| path.parent().unwrap().to_path_buf())
+// .read_dir()?
+// .map(Result::unwrap)
+// .map(|e| e.path())
+// .filter(|e| {
+// e.extension() == Some(OsStr::new("yaml"))
+// || e.extension() == Some(OsStr::new("jelly"))
+// });
- let mut children = Vec::new();
- for p in paths {
- let opts: ImportOptions = if p.extension() == Some(OsStr::new("jelly")) {
- serde_json::from_reader(File::open(&p)?)?
- } else {
- serde_yaml::from_reader(File::open(&p)?)?
- };
- if opts.id != id {
- children.push(opts.id);
- }
- }
- db.add_partial_node(
- &id,
- index_path,
- Node {
- private: NodePrivate::default(),
- public: NodePublic {
- children,
- ..Default::default()
- },
- },
- )?;
- }
- }
- Ok(errors)
-}
+// let mut children = Vec::new();
+// for p in paths {
+// let opts: ImportOptions = if p.extension() == Some(OsStr::new("jelly")) {
+// serde_json::from_reader(File::open(&p)?)?
+// } else {
+// serde_yaml::from_reader(File::open(&p)?)?
+// };
+// if opts.id != id {
+// children.push(opts.id);
+// }
+// }
+// db.add_partial_node(
+// &id,
+// index_path,
+// Node {
+// private: NodePrivate::default(),
+// public: NodePublic {
+// children,
+// ..Default::default()
+// },
+// },
+// )?;
+// }
+// }
+// Ok(errors)
+// }
-pub fn infer_id_from_path(path: &Path) -> anyhow::Result<String> {
- let f = path
- .file_stem()
- .ok_or(anyhow!("no filename"))?
- .to_str()
- .ok_or(anyhow!("non utf8 filename"))?;
+// pub fn infer_id_from_path(path: &Path) -> anyhow::Result<String> {
+// let f = path
+// .file_stem()
+// .ok_or(anyhow!("no filename"))?
+// .to_str()
+// .ok_or(anyhow!("non utf8 filename"))?;
- if let Some(mat) = RE_YOUTUBE_ID.captures(f) {
- let id = mat.get(1).unwrap().as_str();
- return Ok(format!("youtube-{id}"));
- }
+// if let Some(mat) = RE_YOUTUBE_ID.captures(f) {
+// let id = mat.get(1).unwrap().as_str();
+// return Ok(format!("youtube-{id}"));
+// }
- let mut fsan = String::with_capacity(f.len());
- for c in f.chars() {
- fsan.extend(match c {
- 'A'..='Z' | 'a'..='z' | '0'..='9' | '_' | '-' => Some(c),
- ' ' => Some('-'),
- _ => None,
- });
- }
- Ok(fsan)
-}
+// let mut fsan = String::with_capacity(f.len());
+// for c in f.chars() {
+// fsan.extend(match c {
+// 'A'..='Z' | 'a'..='z' | '0'..='9' | '_' | '-' => Some(c),
+// ' ' => Some('-'),
+// _ => None,
+// });
+// }
+// Ok(fsan)
+// }
-fn merge_node(x: Node, y: Node) -> anyhow::Result<Node> {
- let (media, source) = match (
- x.public.media,
- y.public.media,
- x.private.source,
- y.private.source,
- ) {
- (Some(x), Some(y), Some(sx), Some(sy)) => {
- let k = merge_media(x, y, sx, sy);
- (Some(k.0), Some(k.1))
- }
- (Some(x), None, Some(sx), None) => (Some(x), Some(sx)),
- (None, Some(y), None, Some(sy)) => (Some(y), Some(sy)),
- (None, None, None, None) => (None, None),
- _ => bail!("invalid node. source and media dont agree."),
- };
- Ok(Node {
- public: NodePublic {
- kind: x.public.kind.or(y.public.kind),
- title: x.public.title.or(y.public.title),
- subtitle: x.public.subtitle.or(y.public.subtitle),
- id: x.public.id.or(y.public.id),
- path: vec![],
- children: merge_children(x.public.children, y.public.children),
- tagline: x.public.tagline.or(y.public.tagline),
- description: x.public.description.or(y.public.description),
- release_date: x.public.release_date.or(y.public.release_date),
- index: x.public.index.or(y.public.index),
- media,
- ratings: x
- .public
- .ratings
- .into_iter()
- .chain(y.public.ratings)
- .collect(),
- federated: None,
- poster: x.public.poster.or(y.public.poster),
- backdrop: x.public.backdrop.or(y.public.backdrop),
- },
- private: NodePrivate {
- id: x.private.id.or(y.private.id),
- source,
- backdrop: None,
- poster: None,
- },
- })
-}
+// fn merge_node(x: Node, y: Node) -> anyhow::Result<Node> {
+// let (media, source) = match (
+// x.public.media,
+// y.public.media,
+// x.private.source,
+// y.private.source,
+// ) {
+// (Some(x), Some(y), Some(sx), Some(sy)) => {
+// let k = merge_media(x, y, sx, sy);
+// (Some(k.0), Some(k.1))
+// }
+// (Some(x), None, Some(sx), None) => (Some(x), Some(sx)),
+// (None, Some(y), None, Some(sy)) => (Some(y), Some(sy)),
+// (None, None, None, None) => (None, None),
+// _ => bail!("invalid node. source and media dont agree."),
+// };
+// Ok(Node {
+// public: NodePublic {
+// kind: x.public.kind.or(y.public.kind),
+// title: x.public.title.or(y.public.title),
+// subtitle: x.public.subtitle.or(y.public.subtitle),
+// id: x.public.id.or(y.public.id),
+// path: vec![],
+// children: merge_children(x.public.children, y.public.children),
+// tagline: x.public.tagline.or(y.public.tagline),
+// description: x.public.description.or(y.public.description),
+// release_date: x.public.release_date.or(y.public.release_date),
+// index: x.public.index.or(y.public.index),
+// media,
+// ratings: x
+// .public
+// .ratings
+// .into_iter()
+// .chain(y.public.ratings)
+// .collect(),
+// federated: None,
+// poster: x.public.poster.or(y.public.poster),
+// backdrop: x.public.backdrop.or(y.public.backdrop),
+// },
+// private: NodePrivate {
+// id: x.private.id.or(y.private.id),
+// source,
+// backdrop: None,
+// poster: None,
+// },
+// })
+// }
-fn merge_children(mut a: Vec<String>, b: Vec<String>) -> Vec<String> {
- let acont = HashSet::<_, RandomState>::from_iter(a.clone());
- for el in b {
- if !acont.contains(&el) {
- a.push(el)
- }
- }
- a
-}
-fn merge_media(
- x: MediaInfo,
- y: MediaInfo,
- sx: Vec<TrackSource>,
- sy: Vec<TrackSource>,
-) -> (MediaInfo, Vec<TrackSource>) {
- let mut tracks: Vec<SourceTrack> = Vec::new();
- let mut source: Vec<TrackSource> = Vec::new();
- for (t, s) in x
- .tracks
- .into_iter()
- .zip(sx.into_iter())
- .chain(y.tracks.into_iter().zip(sy.into_iter()))
- {
- let mut remove = None;
- let mut skip = false;
- for (i, ot) in tracks.iter().enumerate() {
- if t.name == ot.name
- && t.kind == ot.kind
- && t.language == ot.language
- && t.codec == ot.codec
- {
- if t.federated.len() < ot.federated.len() {
- remove = Some(i);
- } else {
- skip = true;
- }
- }
- }
- if let Some(r) = remove {
- tracks.swap_remove(r);
- source.swap_remove(r);
- }
- if !skip {
- tracks.push(t);
- source.push(s);
- }
- }
- (
- MediaInfo {
- duration: x.duration * 0.5 + y.duration * 0.5,
- tracks,
- chapters: if x.chapters.len() > y.chapters.len() {
- x.chapters
- } else {
- y.chapters
- },
- },
- source,
- )
-}
+// fn merge_children(mut a: Vec<String>, b: Vec<String>) -> Vec<String> {
+// let acont = HashSet::<_, RandomState>::from_iter(a.clone());
+// for el in b {
+// if !acont.contains(&el) {
+// a.push(el)
+// }
+// }
+// a
+// }
+// fn merge_media(
+// x: MediaInfo,
+// y: MediaInfo,
+// sx: Vec<TrackSource>,
+// sy: Vec<TrackSource>,
+// ) -> (MediaInfo, Vec<TrackSource>) {
+// let mut tracks: Vec<SourceTrack> = Vec::new();
+// let mut source: Vec<TrackSource> = Vec::new();
+// for (t, s) in x
+// .tracks
+// .into_iter()
+// .zip(sx.into_iter())
+// .chain(y.tracks.into_iter().zip(sy.into_iter()))
+// {
+// let mut remove = None;
+// let mut skip = false;
+// for (i, ot) in tracks.iter().enumerate() {
+// if t.name == ot.name
+// && t.kind == ot.kind
+// && t.language == ot.language
+// && t.codec == ot.codec
+// {
+// if t.federated.len() < ot.federated.len() {
+// remove = Some(i);
+// } else {
+// skip = true;
+// }
+// }
+// }
+// if let Some(r) = remove {
+// tracks.swap_remove(r);
+// source.swap_remove(r);
+// }
+// if !skip {
+// tracks.push(t);
+// source.push(s);
+// }
+// }
+// (
+// MediaInfo {
+// duration: x.duration * 0.5 + y.duration * 0.5,
+// tracks,
+// chapters: if x.chapters.len() > y.chapters.len() {
+// x.chapters
+// } else {
+// y.chapters
+// },
+// },
+// source,
+// )
+// }
-static SEM_REMOTE_IMPORT: Semaphore = Semaphore::const_new(16);
+// static SEM_REMOTE_IMPORT: Semaphore = Semaphore::const_new(16);
-#[async_recursion]
-async fn import_remote(
- id: String,
- host: &str,
- db: &impl ImportStorage,
- session: &Arc<Session>,
- index_path: &[usize],
-) -> anyhow::Result<()> {
- let _permit = SEM_REMOTE_IMPORT.acquire().await.unwrap();
- info!("loading federated node {id:?}");
+// #[async_recursion]
+// async fn import_remote(
+// id: String,
+// host: &str,
+// db: &impl ImportStorage,
+// session: &Arc<Session>,
+// index_path: &[usize],
+// ) -> anyhow::Result<()> {
+// let _permit = SEM_REMOTE_IMPORT.acquire().await.unwrap();
+// info!("loading federated node {id:?}");
- let mut node = session.node(&id).await.context("fetching remote node")?;
- let mut node_ext = session
- .node_extended(&id)
- .await
- .context("fetching extended remote node")?;
+// let mut node = session.node(&id).await.context("fetching remote node")?;
+// let mut node_ext = session
+// .node_extended(&id)
+// .await
+// .context("fetching extended remote node")?;
- let track_sources = if let Some(media) = &mut node.media {
- let mut track_sources = Vec::new();
- for (i, t) in media.tracks.iter_mut().enumerate() {
- t.federated.push(host.to_owned());
- track_sources.push(TrackSource::Remote(i))
- }
- Some(track_sources)
- } else {
- None
- };
+// let track_sources = if let Some(media) = &mut node.media {
+// let mut track_sources = Vec::new();
+// for (i, t) in media.tracks.iter_mut().enumerate() {
+// t.federated.push(host.to_owned());
+// track_sources.push(TrackSource::Remote(i))
+// }
+// Some(track_sources)
+// } else {
+// None
+// };
- drop(_permit);
+// drop(_permit);
- let mut node = Node {
- public: node.clone(),
- private: NodePrivate {
- backdrop: None,
- poster: None,
- id: None,
- source: track_sources,
- },
- };
- make_opt_asset_federated(host, &mut node.public.backdrop)?;
- make_opt_asset_federated(host, &mut node.public.poster)?;
- for g in node_ext.people.values_mut() {
- for a in g {
- make_opt_asset_federated(host, &mut a.person.headshot)?;
- }
- }
+// let mut node = Node {
+// public: node.clone(),
+// private: NodePrivate {
+// backdrop: None,
+// poster: None,
+// id: None,
+// source: track_sources,
+// },
+// };
+// make_opt_asset_federated(host, &mut node.public.backdrop)?;
+// make_opt_asset_federated(host, &mut node.public.poster)?;
+// for g in node_ext.people.values_mut() {
+// for a in g {
+// make_opt_asset_federated(host, &mut a.person.headshot)?;
+// }
+// }
- debug!("adding {id}");
- db.add_partial_node(&id, index_path, node.clone())?;
- db.add_partial_node_ext(&id, index_path, node_ext)?;
+// debug!("adding {id}");
+// db.add_partial_node(&id, index_path, node.clone())?;
+// db.add_partial_node_ext(&id, index_path, node_ext)?;
- let mut children: FuturesUnordered<_> = node
- .public
- .children
- .iter()
- .map(|c| import_remote(c.to_owned(), host, db, session, index_path))
- .collect();
+// let mut children: FuturesUnordered<_> = node
+// .public
+// .children
+// .iter()
+// .map(|c| import_remote(c.to_owned(), host, db, session, index_path))
+// .collect();
- while let Some(r) = children.next().await {
- r?;
- }
+// while let Some(r) = children.next().await {
+// r?;
+// }
- Ok(())
-}
+// Ok(())
+// }
-pub fn make_opt_asset_federated(host: &str, p: &mut Option<Asset>) -> anyhow::Result<()> {
- if let Some(a) = p {
- make_asset_federated(host, a)?
- }
- Ok(())
-}
-pub fn make_asset_federated(host: &str, p: &mut Asset) -> anyhow::Result<()> {
- let data = base64::engine::general_purpose::URL_SAFE.decode(&p.0)?;
- *p = AssetInner::Federated {
- host: host.to_owned(),
- asset: data,
- }
- .ser();
- Ok(())
-}
+// pub fn make_opt_asset_federated(host: &str, p: &mut Option<Asset>) -> anyhow::Result<()> {
+// if let Some(a) = p {
+// make_asset_federated(host, a)?
+// }
+// Ok(())
+// }
+// pub fn make_asset_federated(host: &str, p: &mut Asset) -> anyhow::Result<()> {
+// let data = base64::engine::general_purpose::URL_SAFE.decode(&p.0)?;
+// *p = AssetInner::Federated {
+// host: host.to_owned(),
+// asset: data,
+// }
+// .ser();
+// Ok(())
+// }
diff --git a/matroska/Cargo.toml b/matroska/Cargo.toml
index a02032d..23c9c5a 100644
--- a/matroska/Cargo.toml
+++ b/matroska/Cargo.toml
@@ -5,6 +5,6 @@ edition = "2021"
[dependencies]
ebml_derive = { path = "../ebml_derive" }
-log = "0.4.22"
-env_logger = "0.11.5"
-thiserror = "1.0.66"
+log = "0.4.25"
+env_logger = "0.11.6"
+thiserror = "2.0.11"
diff --git a/remuxer/Cargo.toml b/remuxer/Cargo.toml
index e931b85..3386717 100644
--- a/remuxer/Cargo.toml
+++ b/remuxer/Cargo.toml
@@ -8,9 +8,9 @@ jellycommon = { path = "../common" }
jellymatroska = { path = "../matroska" }
jellybase = { path = "../base" }
-tokio = { version = "1.41.0", features = ["io-util"] }
-anyhow = "1.0.92"
+tokio = { version = "1.43.0", features = ["io-util"] }
+anyhow = "1.0.95"
log = { workspace = true }
-serde = { version = "1.0.214", features = ["derive"] }
+serde = { version = "1.0.217", features = ["derive"] }
bincode = { version = "2.0.0-rc.3", features = ["serde"] }
diff --git a/remuxer/src/fragment.rs b/remuxer/src/fragment.rs
index 872b1e0..55992db 100644
--- a/remuxer/src/fragment.rs
+++ b/remuxer/src/fragment.rs
@@ -9,7 +9,7 @@ use crate::{
segment_extractor::SegmentExtractIter,
};
use anyhow::{anyhow, Context, Result};
-use jellycommon::{LocalTrack, NodePublic, SourceTrackKind};
+use jellycommon::{LocalTrack, Node, SourceTrackKind};
use jellymatroska::{read::EbmlReader, write::EbmlWriter, Master, MatroskaTag};
use log::{debug, info};
use std::{
@@ -23,7 +23,7 @@ const FRAGMENT_LENGTH: f64 = 2.;
pub fn fragment_index(
path_base: &Path,
- item: &NodePublic,
+ item: &Node,
local_track: &LocalTrack,
track_index: usize,
) -> Result<Vec<Range<f64>>> {
@@ -81,7 +81,7 @@ pub fn fragment_index(
pub fn write_fragment_into(
writer: impl Write,
path_base: &Path,
- item: &NodePublic,
+ item: &Node,
local_track: &LocalTrack,
track: usize,
webm: bool,
diff --git a/remuxer/src/metadata.rs b/remuxer/src/metadata.rs
index 3fd82ce..47b12f0 100644
--- a/remuxer/src/metadata.rs
+++ b/remuxer/src/metadata.rs
@@ -5,7 +5,7 @@
*/
use anyhow::{anyhow, bail, Context, Result};
use bincode::{Decode, Encode};
-use jellycommon::{Chapter, LocalTrack, SourceTrack, SourceTrackKind};
+use jellycommon::{Chapter, LocalTrack, SourceTrack, SourceTrackKind, TrackSource};
use jellymatroska::{
matroska::MatroskaTag,
read::EbmlReader,
@@ -343,16 +343,16 @@ fn import_read_segment(segment: &mut Unflatten) -> Result<MatroskaMetadata> {
m.tracks.push(SourceTrack {
federated: vec![],
default_duration,
+ source: TrackSource::Local(LocalTrack {
+ track: track_index as usize,
+ path: PathBuf::new(),
+ codec_private,
+ }),
name: name.unwrap_or_else(|| "unnamed".to_string()),
codec: codec.unwrap(),
language: language.unwrap_or_else(|| "none".to_string()),
kind,
});
- m.track_sources.push(LocalTrack {
- track: track_index as usize,
- path: PathBuf::new(),
- codec_private,
- })
}
MatroskaTag::Crc32(_) => {}
_ => warn!("(rst) tag ignored: {item:?}"),
diff --git a/remuxer/src/remux.rs b/remuxer/src/remux.rs
index 9419847..b5ecfed 100644
--- a/remuxer/src/remux.rs
+++ b/remuxer/src/remux.rs
@@ -10,7 +10,7 @@ use crate::{
use anyhow::{anyhow, Context};
use jellycommon::{
seek_index::{BlockIndex, SeekIndex},
- LocalTrack, NodePublic, SourceTrack,
+ LocalTrack, Node, SourceTrack,
};
use jellymatroska::{
read::EbmlReader,
@@ -38,7 +38,7 @@ pub fn remux_stream_into(
writer: impl Write,
range: Range<usize>,
path_base: PathBuf,
- item: NodePublic,
+ item: &Node,
track_sources: Vec<LocalTrack>,
selection: Vec<usize>,
webm: bool,
@@ -106,8 +106,8 @@ pub fn remux_stream_into(
output.write_tag(&MatroskaTag::Info(Master::Collected(vec![
MatroskaTag::TimestampScale(1_000_000),
- MatroskaTag::Duration(item.media.unwrap().duration * 1000.0),
- MatroskaTag::Title(item.title.unwrap_or_default().clone()),
+ MatroskaTag::Duration(item.media.as_ref().unwrap().duration * 1000.0),
+ MatroskaTag::Title(item.title.clone().unwrap_or_default()),
MatroskaTag::MuxingApp("jellyremux".to_string()),
MatroskaTag::WritingApp("jellything".to_string()),
])))?;
diff --git a/server/Cargo.toml b/server/Cargo.toml
index 2a52754..5af4ca8 100644
--- a/server/Cargo.toml
+++ b/server/Cargo.toml
@@ -10,17 +10,17 @@ jellystream = { path = "../stream" }
jellytranscoder = { path = "../transcoder" }
jellyimport = { path = "../import" }
-serde = { version = "1.0.214", features = ["derive"] }
+serde = { version = "1.0.217", features = ["derive"] }
bincode = { version = "2.0.0-rc.3", features = ["serde", "derive"] }
-serde_json = "1.0.132"
+serde_json = "1.0.138"
log = { workspace = true }
anyhow = { workspace = true }
-env_logger = "0.11.5"
-rand = "0.8.5"
+env_logger = "0.11.6"
+rand = "0.9.0"
base64 = "0.22.1"
-chrono = { version = "0.4.38", features = ["serde"] }
-vte = "0.13.0"
+chrono = { version = "0.4.39", features = ["serde"] }
+vte = "0.14.1"
chashmap = "2.2.2"
humansize = "2.1.3"
@@ -30,14 +30,14 @@ aes-gcm-siv = "0.11.1"
async-recursion = "1.1.1"
futures = "0.3.31"
tokio = { workspace = true }
-tokio-util = { version = "0.7.12", features = ["io", "io-util"] }
+tokio-util = { version = "0.7.13", features = ["io", "io-util"] }
markup = "0.15.0"
rocket = { workspace = true, features = ["secrets", "json"] }
rocket_ws = { workspace = true }
[build-dependencies]
-glob = "0.3.1"
+glob = "0.3.2"
[features]
bypass-auth = []
diff --git a/server/src/routes/mod.rs b/server/src/routes/mod.rs
index 33f1c69..45dd89a 100644
--- a/server/src/routes/mod.rs
+++ b/server/src/routes/mod.rs
@@ -30,15 +30,15 @@ use ui::{
},
admin::{
log::r_admin_log,
- r_admin_dashboard, r_admin_delete_cache, r_admin_import, r_admin_invite,
- r_admin_remove_invite, r_admin_transcode_posters,
+ r_admin_dashboard, r_admin_delete_cache, r_admin_invite, r_admin_remove_invite,
+ r_admin_transcode_posters,
user::{r_admin_remove_user, r_admin_user, r_admin_user_permission, r_admin_users},
},
- assets::{r_asset, r_item_assets, r_node_thumbnail, r_person_asset},
+ assets::{r_asset, r_item_backdrop, r_item_poster, r_node_thumbnail, r_person_asset},
browser::r_all_items_filter,
error::{r_api_catch, r_catch},
home::{r_home, r_home_unpriv},
- node::{r_library_node_ext, r_library_node_filter},
+ node::r_library_node_filter,
player::r_player,
search::r_search,
style::{r_assets_font, r_assets_js, r_assets_js_map, r_assets_style},
@@ -100,12 +100,12 @@ pub fn build_rocket(database: DataAcid, federation: Federation) -> Rocket<Build>
r_streamsync,
r_favicon,
r_asset,
- r_item_assets,
+ r_item_backdrop,
+ r_item_poster,
r_person_asset,
r_search,
r_all_items_filter,
r_library_node_filter,
- r_library_node_ext,
r_assets_style,
r_assets_font,
r_assets_js,
@@ -130,7 +130,6 @@ pub fn build_rocket(database: DataAcid, federation: Federation) -> Rocket<Build>
r_admin_users,
r_admin_remove_invite,
r_admin_user_permission,
- r_admin_import,
r_admin_delete_cache,
r_admin_transcode_posters,
r_admin_log,
diff --git a/server/src/routes/stream.rs b/server/src/routes/stream.rs
index 756c502..3500ee4 100644
--- a/server/src/routes/stream.rs
+++ b/server/src/routes/stream.rs
@@ -57,22 +57,21 @@ pub async fn r_stream(
.get(db, id)?
.only_if_permitted(&session.user.permissions)
.ok_or(anyhow!("node does not exist"))?;
- let source = node
- .private
- .source
+ let media = node
+ .media
.as_ref()
.ok_or(anyhow!("item does not contain media"))?;
// TODO its unclear how requests with multiple tracks should be handled.
if spec.track.len() == 1 {
let ti = spec.track[0];
- if let TrackSource::Remote(remote_index) = source[ti] {
+ if let TrackSource::Remote(remote_index) = media.tracks[ti].source {
session
.user
.permissions
.assert(&UserPermission::FederatedContent)?;
- let track = &node.public.media.ok_or(anyhow!("no media"))?.tracks[ti];
+ let track = &node.media.ok_or(anyhow!("no media"))?.tracks[ti];
let host = track
.federated
.last()
@@ -100,7 +99,7 @@ pub async fn r_stream(
.await?;
let uri = session.stream_url(
- node.public.id.as_ref().unwrap(),
+ &node.slug,
&StreamSpec {
track: vec![remote_index],
..spec
diff --git a/server/src/routes/ui/admin/log.rs b/server/src/routes/ui/admin/log.rs
index 884ad7a..b123ada 100644
--- a/server/src/routes/ui/admin/log.rs
+++ b/server/src/routes/ui/admin/log.rs
@@ -136,9 +136,7 @@ impl log::Log for Log {
fn vt100_to_html(s: &str) -> String {
let mut out = HtmlOut::default();
let mut st = vte::Parser::new();
- for b in s.bytes() {
- st.advance(&mut out, b);
- }
+ st.advance(&mut out, s.as_bytes());
out.s
}
diff --git a/server/src/routes/ui/admin/mod.rs b/server/src/routes/ui/admin/mod.rs
index 25f1f42..6e19373 100644
--- a/server/src/routes/ui/admin/mod.rs
+++ b/server/src/routes/ui/admin/mod.rs
@@ -26,12 +26,10 @@ use jellybase::{
database::{
redb::{ReadableTable, ReadableTableMetadata},
tantivy::query::Bm25StatisticsProvider,
- TableExt, T_INVITE, T_NODE, T_NODE_EXTENDED, T_USER_NODE,
+ TableExt, T_INVITE, T_NODE, T_USER_NODE,
},
- federation::Federation,
CONF,
};
-use jellyimport::{import, is_importing, IMPORT_ERRORS};
use markup::DynRender;
use rand::Rng;
use rocket::{form::Form, get, post, FromForm, State};
@@ -66,7 +64,7 @@ pub async fn admin_dashboard<'a>(
};
let flash = flash.map(|f| f.map_err(|e| format!("{e:?}")));
- let last_import_err = IMPORT_ERRORS.read().await.to_owned();
+ // let last_import_err = IMPORT_ERRORS.read().await.to_owned();
let database = database.to_owned();
Ok(LayoutPage {
@@ -74,28 +72,28 @@ pub async fn admin_dashboard<'a>(
content: markup::new! {
h1 { "Admin Panel" }
@FlashDisplay { flash: flash.clone() }
- @if !last_import_err.is_empty() {
- section.message.error {
- p.error {"The last import resulted in at least one error:"}
- ol { @for e in &last_import_err {
- li.error { pre.error { @e } }
- }}
- }
- }
+ // @if !last_import_err.is_empty() {
+ // section.message.error {
+ // p.error {"The last import resulted in at least one error:"}
+ // ol { @for e in &last_import_err {
+ // li.error { pre.error { @e } }
+ // }}
+ // }
+ // }
ul {
li{a[href=uri!(r_admin_log(true))] { "Server Log (Warnings only)" }}
li{a[href=uri!(r_admin_log(false))] { "Server Log (Full) " }}
}
h2 { "Library" }
- @if is_importing() {
- section.message { p.warn { "An import is currently running." } }
- }
+ // @if is_importing() {
+ // section.message { p.warn { "An import is currently running." } }
+ // }
@if is_transcoding() {
section.message { p.warn { "Currently transcoding posters." } }
}
- form[method="POST", action=uri!(r_admin_import())] {
- input[type="submit", disabled=is_importing(), value="(Re-)Import Library"];
- }
+ // form[method="POST", action=uri!(r_admin_import())] {
+ // input[type="submit", disabled=is_importing(), value="(Re-)Import Library"];
+ // }
form[method="POST", action=uri!(r_admin_transcode_posters())] {
input[type="submit", disabled=is_transcoding(), value="Transcode all posters with low resolution"];
}
@@ -133,7 +131,7 @@ pub async fn r_admin_invite(
_session: AdminSession,
database: &State<DataAcid>,
) -> MyResult<DynLayoutPage<'static>> {
- let i = format!("{}", rand::thread_rng().gen::<u128>());
+ let i = format!("{}", rand::rng().random::<u128>());
T_INVITE.insert(database, &*i, ())?;
admin_dashboard(database, Some(Ok(format!("Invite: {}", i)))).await
@@ -158,24 +156,24 @@ pub async fn r_admin_remove_invite(
admin_dashboard(database, Some(Ok("Invite invalidated".into()))).await
}
-#[post("/admin/import")]
-pub async fn r_admin_import(
- session: AdminSession,
- database: &State<DataAcid>,
- federation: &State<Federation>,
-) -> MyResult<DynLayoutPage<'static>> {
- drop(session);
- let t = Instant::now();
- let r = import(database, federation).await;
- admin_dashboard(
- database,
- Some(
- r.map_err(|e| e.into())
- .map(|_| format!("Import successful; took {:?}", t.elapsed())),
- ),
- )
- .await
-}
+// #[post("/admin/import")]
+// pub async fn r_admin_import(
+// session: AdminSession,
+// database: &State<DataAcid>,
+// federation: &State<Federation>,
+// ) -> MyResult<DynLayoutPage<'static>> {
+// drop(session);
+// let t = Instant::now();
+// let r = import(database, federation).await;
+// admin_dashboard(
+// database,
+// Some(
+// r.map_err(|e| e.into())
+// .map(|_| format!("Import successful; took {:?}", t.elapsed())),
+// ),
+// )
+// .await
+// }
#[post("/admin/delete_cache")]
pub async fn r_admin_delete_cache(
@@ -218,7 +216,7 @@ pub async fn r_admin_transcode_posters(
let nodes = txn.open_table(T_NODE)?;
for node in nodes.iter()? {
let (_, node) = node?;
- if let Some(poster) = &node.value().0.public.poster {
+ if let Some(poster) = &node.value().0.poster {
let asset = AssetInner::deser(&poster.0)?;
if asset.is_federated() {
continue;
@@ -246,7 +244,6 @@ fn db_stats(db: &DataAcid) -> anyhow::Result<DynRender> {
let txn = db.inner.begin_read()?;
let stats = [
("node", txn.open_table(T_NODE)?.stats()?),
- ("node-ext", txn.open_table(T_NODE_EXTENDED)?.stats()?),
("user", txn.open_table(T_USER_NODE)?.stats()?),
("user-node", txn.open_table(T_USER_NODE)?.stats()?),
("invite", txn.open_table(T_INVITE)?.stats()?),
diff --git a/server/src/routes/ui/assets.rs b/server/src/routes/ui/assets.rs
index ad31240..aeb4eff 100644
--- a/server/src/routes/ui/assets.rs
+++ b/server/src/routes/ui/assets.rs
@@ -9,16 +9,15 @@ use base64::Engine;
use jellybase::{
assetfed::AssetInner,
cache::async_cache_file,
- database::{DataAcid, TableExt, T_NODE, T_NODE_EXTENDED},
+ database::{DataAcid, TableExt, T_NODE},
federation::Federation,
permission::NodePermissionExt,
CONF,
};
-pub use jellycommon::AssetRole;
use jellycommon::{LocalTrack, PeopleGroup, SourceTrackKind, TrackSource};
use log::info;
use rocket::{get, http::ContentType, response::Redirect, State};
-use std::path::PathBuf;
+use std::{path::PathBuf, str::FromStr};
pub const AVIF_QUALITY: f32 = 50.;
pub const AVIF_SPEED: u8 = 5;
@@ -66,12 +65,11 @@ pub async fn resolve_asset(asset: AssetInner) -> anyhow::Result<PathBuf> {
}
}
-#[get("/n/<id>/asset?<role>&<width>")]
-pub async fn r_item_assets(
+#[get("/n/<id>/poster?<width>")]
+pub async fn r_item_poster(
session: Session,
db: &State<DataAcid>,
id: &str,
- role: AssetRole,
width: Option<usize>,
) -> MyResult<Redirect> {
let node = T_NODE
@@ -79,26 +77,45 @@ pub async fn r_item_assets(
.only_if_permitted(&session.user.permissions)
.ok_or(anyhow!("node does not exist"))?;
- let mut asset = match role {
- AssetRole::Backdrop => node.public.backdrop,
- AssetRole::Poster => node.public.poster,
+ let mut asset = node.poster;
+ if asset.is_none() {
+ if let Some(parent) = &node.parents.last() {
+ let parent = T_NODE
+ .get(db, parent.as_str())?
+ .ok_or(anyhow!("node does not exist"))?;
+ asset = parent.poster;
+ }
};
+ let asset = asset.unwrap_or_else(|| {
+ AssetInner::Assets(format!("fallback-{:?}.avif", node.kind.unwrap_or_default()).into())
+ .ser()
+ });
+ Ok(Redirect::temporary(rocket::uri!(r_asset(asset.0, width))))
+}
+#[get("/n/<id>/backdrop?<width>")]
+pub async fn r_item_backdrop(
+ session: Session,
+ db: &State<DataAcid>,
+ id: &str,
+ width: Option<usize>,
+) -> MyResult<Redirect> {
+ let node = T_NODE
+ .get(db, id)?
+ .only_if_permitted(&session.user.permissions)
+ .ok_or(anyhow!("node does not exist"))?;
+
+ let mut asset = node.poster;
if asset.is_none() {
- if let Some(parent) = &node.public.path.last() {
+ if let Some(parent) = &node.parents.last() {
let parent = T_NODE
.get(db, parent.as_str())?
.ok_or(anyhow!("node does not exist"))?;
- asset = match role {
- AssetRole::Backdrop => parent.public.backdrop,
- AssetRole::Poster => parent.public.poster,
- };
+ asset = parent.poster;
}
};
let asset = asset.unwrap_or_else(|| {
- AssetInner::Assets(
- format!("fallback-{:?}.avif", node.public.kind.unwrap_or_default()).into(),
- )
- .ser()
+ AssetInner::Assets(format!("fallback-{:?}.avif", node.kind.unwrap_or_default()).into())
+ .ser()
});
Ok(Redirect::temporary(rocket::uri!(r_asset(asset.0, width))))
}
@@ -109,7 +126,7 @@ pub async fn r_person_asset(
db: &State<DataAcid>,
id: &str,
index: usize,
- group: PeopleGroup,
+ group: String,
width: Option<usize>,
) -> MyResult<Redirect> {
T_NODE
@@ -117,10 +134,10 @@ pub async fn r_person_asset(
.only_if_permitted(&session.user.permissions)
.ok_or(anyhow!("node does not exist"))?;
- let ext = T_NODE_EXTENDED.get(db, id)?.unwrap_or_default();
- let app = ext
+ let node = T_NODE.get(db, id)?.unwrap_or_default();
+ let app = node
.people
- .get(&group)
+ .get(&PeopleGroup::from_str(&group).map_err(|()| anyhow!("unknown people group"))?)
.ok_or(anyhow!("group has no members"))?
.get(index)
.ok_or(anyhow!("person does not exist"))?;
@@ -150,15 +167,18 @@ pub async fn r_node_thumbnail(
.only_if_permitted(&session.user.permissions)
.ok_or(anyhow!("node does not exist"))?;
- let media = node.public.media.ok_or(anyhow!("no media"))?;
+ let media = node.media.ok_or(anyhow!("no media"))?;
let (thumb_track_index, thumb_track) = media
.tracks
.iter()
.enumerate()
.find(|(_i, t)| matches!(t.kind, SourceTrackKind::Video { .. }))
.ok_or(anyhow!("no video track to create a thumbnail of"))?;
- let source = node.private.source.ok_or(anyhow!("no source"))?;
- let thumb_track_source = &source[thumb_track_index];
+ let source = media
+ .tracks
+ .get(thumb_track_index)
+ .ok_or(anyhow!("no source"))?;
+ let thumb_track_source = source.source.clone();
if t < 0. || t > media.duration {
Err(anyhow!("thumbnail instant not within media duration"))?
diff --git a/server/src/routes/ui/browser.rs b/server/src/routes/ui/browser.rs
index da17271..4faf40b 100644
--- a/server/src/routes/ui/browser.rs
+++ b/server/src/routes/ui/browser.rs
@@ -39,7 +39,6 @@ pub fn r_all_items_filter(
.unwrap()
.map(|z| z.value().0)
.unwrap_or_default();
- let y = y.public;
(x, y, z)
})
.collect::<Vec<_>>();
diff --git a/server/src/routes/ui/home.rs b/server/src/routes/ui/home.rs
index 0a1089a..6f70644 100644
--- a/server/src/routes/ui/home.rs
+++ b/server/src/routes/ui/home.rs
@@ -3,19 +3,14 @@
which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
Copyright (C) 2024 metamuffin <metamuffin.org>
*/
-use super::{
- account::session::Session,
- layout::LayoutPage,
- node::{DatabaseNodeUserDataExt, NodeCard},
-};
+use super::{account::session::Session, layout::LayoutPage, node::NodeCard};
use crate::{
database::DataAcid,
routes::ui::{error::MyResult, layout::DynLayoutPage},
};
-use anyhow::Context;
use chrono::{Datelike, Utc};
use jellybase::{
- database::{redb::ReadableTable, TableExt, T_NODE, T_USER_NODE},
+ database::{redb::ReadableTable, T_NODE, T_USER_NODE},
CONF,
};
use jellycommon::{user::WatchedState, Rating};
@@ -38,7 +33,6 @@ pub fn r_home(sess: Session, db: &State<DataAcid>) -> MyResult<DynLayoutPage> {
.unwrap()
.map(|z| z.value().0)
.unwrap_or_default();
- let y = y.public;
(x, y, z)
})
.collect::<Vec<_>>();
@@ -49,16 +43,14 @@ pub fn r_home(sess: Session, db: &State<DataAcid>) -> MyResult<DynLayoutPage> {
.flat_map(|i| Some(items[cheap_daily_random(i).checked_rem(items.len())?].clone()))
.collect::<Vec<_>>();
- let toplevel = T_NODE
- .get(db, "library")?
- .context("root node missing")?
- .public
- .children
- .into_iter()
- .map(|n| db.get_node_with_userdata(&n, &sess))
- .collect::<anyhow::Result<Vec<_>>>()?
- .into_iter()
- .collect::<Vec<_>>();
+ // let toplevel = T_NODE
+ // .get(db, "library")?
+ // .context("root node missing")?
+ // .into_iter()
+ // .map(|n| db.get_node_with_userdata(&n, &sess))
+ // .collect::<anyhow::Result<Vec<_>>>()?
+ // .into_iter()
+ // .collect::<Vec<_>>();
items.sort_by_key(|(_, n, _)| {
n.ratings
@@ -98,9 +90,9 @@ pub fn r_home(sess: Session, db: &State<DataAcid>) -> MyResult<DynLayoutPage> {
title: "Home".to_string(),
content: markup::new! {
h2 { "Explore " @CONF.brand }
- ul.children.hlist {@for (id, node, udata) in &toplevel {
- li { @NodeCard { id, node, udata } }
- }}
+ // ul.children.hlist {@for (id, node, udata) in &toplevel {
+ // li { @NodeCard { id, node, udata } }
+ // }}
@if !continue_watching.is_empty() {
h2 { "Continue Watching" }
ul.children.hlist {@for (id, node, udata) in &continue_watching {
diff --git a/server/src/routes/ui/node.rs b/server/src/routes/ui/node.rs
index 40faf5a..88f71b7 100644
--- a/server/src/routes/ui/node.rs
+++ b/server/src/routes/ui/node.rs
@@ -4,7 +4,10 @@
Copyright (C) 2024 metamuffin <metamuffin.org>
*/
use super::{
- assets::{rocket_uri_macro_r_item_assets, rocket_uri_macro_r_node_thumbnail},
+ assets::{
+ rocket_uri_macro_r_item_backdrop, rocket_uri_macro_r_item_poster,
+ rocket_uri_macro_r_node_thumbnail,
+ },
error::MyResult,
sort::{filter_and_sort_nodes, NodeFilterSort, NodeFilterSortForm, SortOrder, SortProperty},
};
@@ -14,7 +17,7 @@ use crate::{
api::AcceptJson,
ui::{
account::session::Session,
- assets::{rocket_uri_macro_r_person_asset, AssetRole},
+ assets::rocket_uri_macro_r_person_asset,
layout::{DynLayoutPage, LayoutPage},
player::{rocket_uri_macro_r_player, PlayerConfig},
},
@@ -28,12 +31,12 @@ use crate::{
use anyhow::{anyhow, Result};
use chrono::DateTime;
use jellybase::{
- database::{TableExt, T_NODE, T_NODE_EXTENDED, T_USER_NODE},
+ database::{TableExt, T_NODE, T_USER_NODE},
permission::NodePermissionExt,
};
use jellycommon::{
user::{NodeUserData, WatchedState},
- Chapter, ExtendedNode, MediaInfo, NodeKind, NodePublic, PeopleGroup, Rating, SourceTrackKind,
+ Chapter, MediaInfo, Node, NodeKind, PeopleGroup, Rating, SourceTrackKind,
};
use rocket::{get, serde::json::Json, Either, State};
@@ -43,20 +46,6 @@ pub fn r_library_node(id: String) {
drop(id)
}
-#[get("/n/<id>/extended")]
-pub async fn r_library_node_ext<'a>(
- session: Session,
- id: &'a str,
- db: &'a State<DataAcid>,
-) -> MyResult<Json<ExtendedNode>> {
- T_NODE
- .get(db, id)?
- .only_if_permitted(&session.user.permissions)
- .ok_or(anyhow!("node does not exist"))?;
-
- Ok(Json(T_NODE_EXTENDED.get(db, id)?.unwrap_or_default()))
-}
-
#[get("/n/<id>?<filter..>")]
pub async fn r_library_node_filter<'a>(
session: Session,
@@ -64,13 +53,11 @@ pub async fn r_library_node_filter<'a>(
db: &'a State<DataAcid>,
aj: AcceptJson,
filter: NodeFilterSort,
-) -> MyResult<Either<DynLayoutPage<'a>, Json<NodePublic>>> {
+) -> MyResult<Either<DynLayoutPage<'a>, Json<Node>>> {
let node = T_NODE
.get(db, id)?
.only_if_permitted(&session.user.permissions)
- .ok_or(anyhow!("node does not exist"))?
- .public;
- let node_ext = T_NODE_EXTENDED.get(db, id)?.unwrap_or_default();
+ .ok_or(anyhow!("node does not exist"))?;
let udata = T_USER_NODE
.get(db, &(session.user.name.as_str(), id))?
@@ -80,29 +67,29 @@ pub async fn r_library_node_filter<'a>(
return Ok(Either::Right(Json(node)));
}
- let mut children = node
- .children
- .iter()
- .map(|c| db.get_node_with_userdata(c, &session))
- .collect::<anyhow::Result<Vec<_>>>()?
- .into_iter()
- .collect();
+ // let mut children = node
+ // .children
+ // .iter()
+ // .map(|c| db.get_node_with_userdata(c, &session))
+ // .collect::<anyhow::Result<Vec<_>>>()?
+ // .into_iter()
+ // .collect();
- let path = node
- .path
- .iter()
- .map(|c| {
- Ok((
- c.to_owned(),
- T_NODE
- .get(db, c.as_str())?
- .ok_or(anyhow!("parent node missing"))?
- .public,
- ))
- })
- .collect::<anyhow::Result<Vec<_>>>()?
- .into_iter()
- .collect::<Vec<_>>();
+ // let path = node
+ // .path
+ // .iter()
+ // .map(|c| {
+ // Ok((
+ // c.to_owned(),
+ // T_NODE
+ // .get(db, c.as_str())?
+ // .ok_or(anyhow!("parent node missing"))?
+ // .public,
+ // ))
+ // })
+ // .collect::<anyhow::Result<Vec<_>>>()?
+ // .into_iter()
+ // .collect::<Vec<_>>();
filter_and_sort_nodes(
&filter,
@@ -110,25 +97,26 @@ pub async fn r_library_node_filter<'a>(
NodeKind::Channel => (SortProperty::ReleaseDate, SortOrder::Descending),
_ => (SortProperty::Title, SortOrder::Ascending),
},
- &mut children,
+ // TODO
+ &mut Vec::new(),
);
Ok(Either::Left(LayoutPage {
title: node.title.clone().unwrap_or_default(),
content: markup::new! {
- @NodePage { node: &node, id, udata: &udata, children: &children, path: &path, filter: &filter, node_ext: &node_ext }
+ @NodePage { node: &node, id, udata: &udata, children: &[], path: &[], filter: &filter }
},
..Default::default()
}))
}
markup::define! {
- NodeCard<'a>(id: &'a str, node: &'a NodePublic, udata: &'a NodeUserData) {
+ NodeCard<'a>(id: &'a str, node: &'a Node, udata: &'a NodeUserData) {
@let cls = format!("node card poster {}", aspect_class(node.kind.unwrap_or_default()));
div[class=cls] {
.poster {
a[href=uri!(r_library_node(id))] {
- img[src=uri!(r_item_assets(id, AssetRole::Poster, Some(1024))), loading="lazy"];
+ img[src=uri!(r_item_poster(id, Some(1024))), loading="lazy"];
}
.cardhover.item {
@if node.media.is_some() {
@@ -149,14 +137,14 @@ markup::define! {
}
}
}
- NodePage<'a>(id: &'a str, node: &'a NodePublic, node_ext: &'a ExtendedNode, udata: &'a NodeUserData, children: &'a [(String, NodePublic, NodeUserData)], path: &'a [(String, NodePublic)], filter: &'a NodeFilterSort) {
+ NodePage<'a>(id: &'a str, node: &'a Node, udata: &'a NodeUserData, children: &'a [(String, Node, NodeUserData)], path: &'a [(String, Node)], filter: &'a NodeFilterSort) {
@if !matches!(node.kind.unwrap_or_default(), NodeKind::Collection) {
- img.backdrop[src=uri!(r_item_assets(id, AssetRole::Backdrop, Some(2048))), loading="lazy"];
+ img.backdrop[src=uri!(r_item_backdrop(id, Some(2048))), loading="lazy"];
}
.page.node {
@if !matches!(node.kind.unwrap_or_default(), NodeKind::Collection) {
@let cls = format!("bigposter {}", aspect_class(node.kind.unwrap_or_default()));
- div[class=cls] { img[src=uri!(r_item_assets(id, AssetRole::Poster, Some(2048))), loading="lazy"]; }
+ div[class=cls] { img[src=uri!(r_item_poster(id, Some(2048))), loading="lazy"]; }
}
.title {
h1 { @node.title }
@@ -213,16 +201,16 @@ markup::define! {
}}
}}
}
- @if !node_ext.people.is_empty() {
+ @if !node.people.is_empty() {
h2 { "Cast & Crew" }
- @for (group, people) in &node_ext.people {
+ @for (group, people) in &node.people {
details[open=group==&PeopleGroup::Cast] {
summary { h3 { @format!("{}", group) } }
ul.children.hlist { @for (i, pe) in people.iter().enumerate() {
li { .card."aspect-port" {
.poster {
a[href="#"] {
- img[src=&uri!(r_person_asset(id, i, group, Some(1024))), loading="lazy"];
+ img[src=&uri!(r_person_asset(id, i, group.to_string(), Some(1024))), loading="lazy"];
}
}
.title {
@@ -265,7 +253,7 @@ markup::define! {
}
}
- Props<'a>(node: &'a NodePublic, udata: &'a NodeUserData, full: bool) {
+ Props<'a>(node: &'a Node, udata: &'a NodeUserData, full: bool) {
.props {
@if let Some(m) = &node.media {
p { @format_duration(m.duration) }
@@ -278,9 +266,10 @@ markup::define! {
@DateTime::from_timestamp_millis(*d).unwrap().date_naive().to_string()
}}
}
- @if !node.children.is_empty() {
- p { @format!("{} items", node.children.len()) }
- }
+ // TODO
+ // @if !node.children.is_empty() {
+ // p { @format!("{} items", node.children.len()) }
+ // }
@for (kind, value) in &node.ratings {
@match kind {
Rating::YoutubeLikes => {p{ @format_count(*value as usize) " Likes" }}
@@ -337,21 +326,20 @@ pub trait DatabaseNodeUserDataExt {
&self,
id: &str,
session: &Session,
- ) -> Result<(String, NodePublic, NodeUserData)>;
+ ) -> Result<(String, Node, NodeUserData)>;
}
impl DatabaseNodeUserDataExt for DataAcid {
fn get_node_with_userdata(
&self,
id: &str,
session: &Session,
- ) -> Result<(String, NodePublic, NodeUserData)> {
+ ) -> Result<(String, Node, NodeUserData)> {
Ok((
id.to_owned(),
T_NODE
.get(self, id)?
.only_if_permitted(&session.user.permissions)
- .ok_or(anyhow!("node does not exist: {id}"))?
- .public,
+ .ok_or(anyhow!("node does not exist: {id}"))?,
T_USER_NODE
.get(self, &(session.user.name.as_str(), id))?
.unwrap_or_default(),
diff --git a/server/src/routes/ui/player.rs b/server/src/routes/ui/player.rs
index 55e1303..c5232e1 100644
--- a/server/src/routes/ui/player.rs
+++ b/server/src/routes/ui/player.rs
@@ -11,11 +11,7 @@ use crate::{
database::DataAcid,
routes::{
stream::rocket_uri_macro_r_stream,
- ui::{
- assets::{rocket_uri_macro_r_item_assets, AssetRole},
- error::MyResult,
- layout::DynLayoutPage,
- },
+ ui::{assets::rocket_uri_macro_r_item_backdrop, error::MyResult, layout::DynLayoutPage},
},
uri,
};
@@ -121,13 +117,13 @@ pub fn r_player<'a>(
let conf = player_conf(item.clone(), playing)?;
Ok(Either::Left(LayoutPage {
- title: item.public.title.to_owned().unwrap_or_default(),
+ title: item.title.to_owned().unwrap_or_default(),
class: Some("player"),
content: markup::new! {
@if playing {
video[src=uri!(r_stream(&id, &spec)), controls, preload="auto"]{}
} else {
- img.backdrop[src=uri!(r_item_assets(&id, AssetRole::Backdrop, Some(2048))).to_string()];
+ img.backdrop[src=uri!(r_item_backdrop(&id, Some(2048))).to_string()];
}
@conf
},
@@ -139,7 +135,6 @@ pub fn player_conf<'a>(item: Node, playing: bool) -> anyhow::Result<DynRender<'a
let mut video_tracks = vec![];
let mut sub_tracks = vec![];
let tracks = item
- .public
.media
.clone()
.ok_or(anyhow!("node does not have media"))?
@@ -155,7 +150,7 @@ pub fn player_conf<'a>(item: Node, playing: bool) -> anyhow::Result<DynRender<'a
Ok(markup::new! {
form.playerconf[method = "GET", action = ""] {
- h2 { "Select tracks for " @item.public.title }
+ h2 { "Select tracks for " @item.title }
fieldset.video {
legend { "Video" }
diff --git a/server/src/routes/ui/search.rs b/server/src/routes/ui/search.rs
index 5ca4b51..c1f9865 100644
--- a/server/src/routes/ui/search.rs
+++ b/server/src/routes/ui/search.rs
@@ -51,8 +51,7 @@ pub async fn r_search<'a>(
let node = T_NODE
.get(db, id)?
.only_if_permitted(&session.user.permissions)
- .ok_or(anyhow!("node does not exist"))?
- .public;
+ .ok_or(anyhow!("node does not exist"))?;
let udata = T_USER_NODE
.get(db, &(session.user.name.as_str(), id))?
.unwrap_or_default();
diff --git a/server/src/routes/ui/sort.rs b/server/src/routes/ui/sort.rs
index bcd9fe3..bb71184 100644
--- a/server/src/routes/ui/sort.rs
+++ b/server/src/routes/ui/sort.rs
@@ -1,7 +1,7 @@
use jellycommon::{
helpers::SortAnyway,
user::{NodeUserData, WatchedState},
- NodeKind, NodePublic, Rating,
+ Node, NodeKind, Rating,
};
use markup::RenderAttributeValue;
use rocket::{
@@ -134,7 +134,7 @@ pub enum SortOrder {
pub fn filter_and_sort_nodes(
f: &NodeFilterSort,
default_sort: (SortProperty, SortOrder),
- nodes: &mut Vec<(String, NodePublic, NodeUserData)>,
+ nodes: &mut Vec<(String, Node, NodeUserData)>,
) {
let sort_prop = f.sort_by.unwrap_or(default_sort.0);
nodes.retain(|(_id, node, udata)| {
diff --git a/stream/Cargo.toml b/stream/Cargo.toml
index d476044..b66cfca 100644
--- a/stream/Cargo.toml
+++ b/stream/Cargo.toml
@@ -11,6 +11,6 @@ jellyremuxer = { path = "../remuxer" }
log = { workspace = true }
anyhow = { workspace = true }
-tokio = { version = "1.41.0", features = ["io-util"] }
-tokio-util = { version = "0.7.12", features = ["io", "io-util"] }
-serde_json = "1.0.132"
+tokio = { version = "1.43.0", features = ["io-util"] }
+tokio-util = { version = "0.7.13", features = ["io", "io-util"] }
+serde_json = "1.0.138"
diff --git a/stream/src/fragment.rs b/stream/src/fragment.rs
index 1082e1c..4b4fd44 100644
--- a/stream/src/fragment.rs
+++ b/stream/src/fragment.rs
@@ -36,7 +36,7 @@ pub async fn fragment_stream(
if let Some(profile) = spec.profile {
perms.assert(&UserPermission::Transcode)?;
let location = transcode(
- &format!("{track} {n} {:?}", node.private.source), // TODO maybe not use the entire source
+ &format!("{track} {n} {:?}", node), // TODO maybe not use the entire source
CONF.transcoding_profiles
.get(profile)
.ok_or(anyhow!("profile out of range"))?,
@@ -45,7 +45,7 @@ pub async fn fragment_stream(
if let Err(err) = jellyremuxer::write_fragment_into(
SyncIoBridge::new(b),
&CONF.media_path,
- &node.public,
+ &node,
&local_track,
track,
false,
@@ -69,7 +69,7 @@ pub async fn fragment_stream(
if let Err(err) = jellyremuxer::write_fragment_into(
b,
&CONF.media_path,
- &node.public,
+ &node,
&local_track,
track,
spec.webm.unwrap_or(false),
diff --git a/stream/src/hls.rs b/stream/src/hls.rs
index 342cbde..894d1b6 100644
--- a/stream/src/hls.rs
+++ b/stream/src/hls.rs
@@ -22,7 +22,7 @@ pub async fn hls_master_stream(
_spec: StreamSpec,
mut b: DuplexStream,
) -> Result<()> {
- let media = node.public.media.as_ref().ok_or(anyhow!("no media"))?;
+ let media = node.media.as_ref().ok_or(anyhow!("no media"))?;
let mut out = String::new();
writeln!(out, "#EXTM3U")?;
writeln!(out, "#EXT-X-VERSION:4")?;
@@ -57,14 +57,9 @@ pub async fn hls_variant_stream(
) -> Result<()> {
let local_track = local_tracks.first().ok_or(anyhow!("no track"))?.to_owned();
let track_index = spec.track[0];
- let media_info = node.public.media.to_owned().ok_or(anyhow!("no media?"))?;
+ let media_info = node.media.to_owned().ok_or(anyhow!("no media?"))?;
let frags = spawn_blocking(move || {
- jellyremuxer::fragment::fragment_index(
- &CONF.media_path,
- &node.public,
- &local_track,
- track_index,
- )
+ jellyremuxer::fragment::fragment_index(&CONF.media_path, &node, &local_track, track_index)
})
.await??;
diff --git a/stream/src/jhls.rs b/stream/src/jhls.rs
index 2e45378..ea5cbfc 100644
--- a/stream/src/jhls.rs
+++ b/stream/src/jhls.rs
@@ -26,12 +26,7 @@ pub async fn jhls_index(
.to_owned();
let segments = tokio::task::spawn_blocking(move || {
- jellyremuxer::fragment::fragment_index(
- &CONF.media_path,
- &node.public,
- &local_track,
- spec.track[0],
- )
+ jellyremuxer::fragment::fragment_index(&CONF.media_path, &node, &local_track, spec.track[0])
})
.await??;
diff --git a/stream/src/lib.rs b/stream/src/lib.rs
index a316042..f4cbbf6 100644
--- a/stream/src/lib.rs
+++ b/stream/src/lib.rs
@@ -57,20 +57,18 @@ pub async fn stream(
let (a, b) = duplex(4096);
// TODO remux of mixed remote and local tracks?!
- let track_sources = node
- .private
- .source
- .to_owned()
- .ok_or(anyhow!("node has no media"))?;
+ let track_sources = node.media.to_owned().ok_or(anyhow!("node has no media"))?;
let local_tracks = spec
.track
.iter()
.map(|i| {
anyhow::Ok(
- match track_sources
+ match &track_sources
+ .tracks
.get(*i)
.ok_or(anyhow!("track does not exist"))?
+ .source
{
TrackSource::Local(t) => t.to_owned(),
TrackSource::Remote(_) => bail!("track is not local"),
@@ -109,7 +107,7 @@ async fn remux_stream(
b,
range,
CONF.media_path.to_owned(),
- node.public,
+ &node,
local_tracks,
spec.track,
spec.webm.unwrap_or(false),
diff --git a/stream/src/webvtt.rs b/stream/src/webvtt.rs
index 316e224..d5b2f9a 100644
--- a/stream/src/webvtt.rs
+++ b/stream/src/webvtt.rs
@@ -23,7 +23,7 @@ pub async fn vtt_stream(
let tracki = *spec.track.first().ok_or(anyhow!("no track selected"))?;
let local_track = local_tracks.first().ok_or(anyhow!("no tracks"))?.clone();
- let track = &node.public.media.unwrap().tracks[tracki];
+ let track = &node.media.unwrap().tracks[tracki];
let cp = local_track.codec_private.clone();
let subtitles = async_cache_memory(
@@ -49,11 +49,8 @@ pub async fn vtt_stream(
let output = if json {
serde_json::to_string(subtitles.as_ref())?
} else {
- write_webvtt(
- node.public.title.clone().unwrap_or_default(),
- subtitles.as_ref(),
- )
- .context("writing webvtt")?
+ write_webvtt(node.title.clone().unwrap_or_default(), subtitles.as_ref())
+ .context("writing webvtt")?
};
tokio::task::spawn(async move {
let _ = b.write_all(output.as_bytes()).await;
diff --git a/tool/Cargo.toml b/tool/Cargo.toml
index 7d3a0a5..1383ee6 100644
--- a/tool/Cargo.toml
+++ b/tool/Cargo.toml
@@ -10,19 +10,19 @@ jellyimport = { path = "../import" }
jellyclient = { path = "../client" }
log = { workspace = true }
-env_logger = "0.11.5"
-anyhow = "1.0.92"
+env_logger = "0.11.6"
+anyhow = "1.0.95"
reqwest = { workspace = true }
-indicatif = "0.17.8"
+indicatif = "0.17.11"
tokio = { workspace = true }
-clap = { version = "4.5.20", features = ["derive"] }
-clap_complete = "4.5.36"
+clap = { version = "4.5.27", features = ["derive"] }
+clap_complete = "4.5.43"
-serde = { version = "1.0.214", features = ["derive"] }
-serde_json = "1.0.132"
+serde = { version = "1.0.217", features = ["derive"] }
+serde_json = "1.0.138"
serde_yaml = "0.9.34"
bincode = { version = "2.0.0-rc.3", features = ["serde"] }
base64 = "0.22.1"
-rand = "0.8.5"
+rand = "0.9.0"
dialoguer = { version = "0.11.0", features = ["fuzzy-select"] }
diff --git a/tool/src/add.rs b/tool/src/add.rs
index 7b3861e..59342da 100644
--- a/tool/src/add.rs
+++ b/tool/src/add.rs
@@ -1,15 +1,14 @@
use crate::cli::Action;
use anyhow::{anyhow, bail, Context};
-use dialoguer::{theme::ColorfulTheme, Confirm, FuzzySelect, Input, MultiSelect};
+use dialoguer::{theme::ColorfulTheme, FuzzySelect, Input, MultiSelect};
use jellybase::{CONF, SECRETS};
-use jellycommon::{ImportOptions, ImportSource, TraktKind};
+use jellycommon::TraktKind;
use jellyimport::trakt::Trakt;
use log::warn;
use std::{
fmt::Display,
path::{Path, PathBuf},
};
-use tokio::{fs::File, io::AsyncWriteExt};
pub async fn add(action: Action) -> anyhow::Result<()> {
match action {
@@ -122,39 +121,42 @@ pub async fn add(action: Action) -> anyhow::Result<()> {
})
});
- let mut sources = Vec::new();
- sources.push(ImportSource::Trakt {
- id: trakt_object.ids.trakt.unwrap(),
- kind: trakt_kind,
- });
- if let Some(media) = media {
- sources.push(ImportSource::Media {
- path: media,
- ignore_metadata: true,
- ignore_attachments: false,
- ignore_chapters: false,
- })
- }
+ // TODO
+ drop((id, library_path, trakt_kind));
- let impo = ImportOptions { id, sources };
+ // let mut sources = Vec::new();
+ // sources.push(ImportSource::Trakt {
+ // id: trakt_object.ids.trakt.unwrap(),
+ // kind: trakt_kind,
+ // });
+ // if let Some(media) = media {
+ // sources.push(ImportSource::Media {
+ // path: media,
+ // ignore_metadata: true,
+ // ignore_attachments: false,
+ // ignore_chapters: false,
+ // })
+ // }
- let ypath = CONF
- .library_path
- .join(library_path)
- .join(&impo.id)
- .with_extension("yaml");
+ // let impo = ImportOptions { id, sources };
- if Confirm::with_theme(&theme)
- .with_prompt(format!("Write {:?}?", ypath))
- .default(true)
- .interact()
- .unwrap()
- {
- File::create(ypath)
- .await?
- .write_all(serde_yaml::to_string(&impo)?.as_bytes())
- .await?;
- }
+ // let ypath = CONF
+ // .library_path
+ // .join(library_path)
+ // .join(&impo.id)
+ // .with_extension("yaml");
+
+ // if Confirm::with_theme(&theme)
+ // .with_prompt(format!("Write {:?}?", ypath))
+ // .default(true)
+ // .interact()
+ // .unwrap()
+ // {
+ // File::create(ypath)
+ // .await?
+ // .write_all(serde_yaml::to_string(&impo)?.as_bytes())
+ // .await?;
+ // }
Ok(())
}
diff --git a/transcoder/Cargo.toml b/transcoder/Cargo.toml
index c860927..f1e5062 100644
--- a/transcoder/Cargo.toml
+++ b/transcoder/Cargo.toml
@@ -9,14 +9,14 @@ jellybase = { path = "../base" }
jellyremuxer = { path = "../remuxer" }
log = { workspace = true }
# TODO: change this back to crates.io when pr is merged
-image = "0.25.4"
+image = "0.25.5"
# image = { git = "https://github.com/metamuffin/image-rs", features = [
# "avif-decoder",
# ] }
libavif-image = { version = "0.14.0", default-features = false, features = [
"codec-dav1d",
] }
-anyhow = "1.0.92"
+anyhow = "1.0.95"
rgb = "0.8.50"
rav1e = { version = "0.7.1", default-features = false, features = [
"threading",
diff --git a/transcoder/src/image.rs b/transcoder/src/image.rs
index 3d7cb2d..fda3129 100644
--- a/transcoder/src/image.rs
+++ b/transcoder/src/image.rs
@@ -64,7 +64,7 @@ pub async fn transcode(
file.read_to_end(&mut buf).context("reading image")?;
libavif_image::read(&buf).unwrap().to_rgba8()
} else {
- let reader = image::io::Reader::new(file);
+ let reader = image::ImageReader::new(file);
let reader = reader.with_guessed_format().context("guessing format")?;
debug!("guessed format (or fallback): {:?}", reader.format());
reader.decode().context("decoding image")?.to_rgba8()
diff --git a/transcoder/src/lib.rs b/transcoder/src/lib.rs
index fe44a1c..585c939 100644
--- a/transcoder/src/lib.rs
+++ b/transcoder/src/lib.rs
@@ -3,7 +3,7 @@
which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
Copyright (C) 2024 metamuffin <metamuffin.org>
*/
-#![feature(async_closure, exit_status_error)]
+#![feature(exit_status_error)]
use tokio::sync::Semaphore;
pub mod fragment;