diff --git a/Cargo.lock b/Cargo.lock index a5be630..9c2e1ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -130,6 +130,18 @@ name = "anyhow" version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" +dependencies = [ + "backtrace", +] + +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" +dependencies = [ + "serde", +] [[package]] name = "arrayvec" @@ -166,16 +178,16 @@ checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3" dependencies = [ "concurrent-queue", "event-listener 5.2.0", - "event-listener-strategy 0.5.0", + "event-listener-strategy 0.5.1", "futures-core", "pin-project-lite", ] [[package]] name = "async-compression" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a116f46a969224200a0a97f29cfd4c50e7534e4b4826bd23ea2c3c533039c82c" +checksum = "86a9249d1447a85f95810c620abea82e001fe58a31713fcce614caf52499f905" dependencies = [ "flate2", "futures-core", @@ -186,14 +198,14 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.8.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ae5ebefcc48e7452b4987947920dac9450be1110cadf34d1b8c116bdbaf97c" +checksum = "10b3e585719c2358d2660232671ca8ca4ddb4be4ce8a1842d6c2dc8685303316" dependencies = [ "async-lock 3.3.0", "async-task", "concurrent-queue", - "fastrand 2.0.1", + "fastrand 2.0.2", "futures-lite 2.3.0", "slab", ] @@ -246,8 +258,8 @@ dependencies = [ "futures-io", "futures-lite 2.3.0", "parking", - "polling 3.5.0", - "rustix 0.38.31", + "polling 3.6.0", + "rustix 0.38.32", "slab", "tracing", "windows-sys 0.52.0", @@ -319,7 +331,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -330,13 +342,13 @@ checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799" [[package]] name = "async-trait" -version = "0.1.78" +version = "0.1.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "461abc97219de0eaaf81fe3ef974a540158f3d079c2ab200f891f1a2ef201e85" +checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -356,15 +368,15 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", @@ -403,9 +415,10 @@ name = "bili-sync" version = "2.0.0" dependencies = [ "anyhow", + "arc-swap", "async-stream", "chrono", - "cookie 0.18.0", + "cookie 0.18.1", "dirs", "entity", "env_logger", @@ -438,9 +451,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" dependencies = [ "serde", ] @@ -475,7 +488,7 @@ dependencies = [ "async-channel 2.2.0", "async-lock 3.3.0", "async-task", - "fastrand 2.0.1", + "fastrand 2.0.2", "futures-io", "futures-lite 2.3.0", "piper", @@ -484,9 +497,9 @@ dependencies = [ [[package]] name = "borsh" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f58b559fd6448c6e2fd0adb5720cd98a2506594cafa4737ff98c396f3e82f667" +checksum = "0901fc8eb0aca4c83be0106d6f2db17d86a08dfc2c25f0e84464bf381158add6" dependencies = [ "borsh-derive", "cfg_aliases", @@ -494,15 +507,15 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aadb5b6ccbd078890f6d7003694e33816e6b784358f18e15e7e6d9f065a57cd" +checksum = "51670c3aa053938b0ee3bd67c3817e471e626151131b934038e83c5bf8de48f5" dependencies = [ "once_cell", "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", "syn_derive", ] @@ -542,9 +555,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" @@ -566,9 +579,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "chrono" -version = "0.4.35" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a" +checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" dependencies = [ "android-tzdata", "iana-time-zone", @@ -581,9 +594,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.3" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", "clap_derive", @@ -603,14 +616,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.3" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -653,9 +666,9 @@ dependencies = [ [[package]] name = "cookie" -version = "0.18.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cd91cf61412820176e137621345ee43b3f4423e589e7ae4e50d601d93e35ef8" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" dependencies = [ "time", "version_check", @@ -754,9 +767,9 @@ dependencies = [ [[package]] name = "der" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", "pem-rfc7468", @@ -940,9 +953,9 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feedafcaa9b749175d5ac357452a9d41ea2911da598fde46ce1fe02c37751291" +checksum = "332f51cb23d20b0de8458b86580878211da09bcd4503cb579c225b3d124cabb3" dependencies = [ "event-listener 5.2.0", "pin-project-lite", @@ -959,9 +972,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" [[package]] name = "filenamify" @@ -1115,7 +1128,7 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ - "fastrand 2.0.1", + "fastrand 2.0.2", "futures-core", "futures-io", "parking", @@ -1130,7 +1143,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -1210,9 +1223,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51ee2dd2e4f378392eeff5d51618cd9a63166a2513846bbc55f21cfacd9199d4" +checksum = "816ec7294445779408f36fe57bc5b7fc1cf59664059096c65f905c1c61f58069" dependencies = [ "bytes", "fnv", @@ -1470,9 +1483,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.5" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown 0.14.3", @@ -1486,7 +1499,7 @@ checksum = "0122b7114117e64a63ac49f752a5ca4624d534c7b1c7de796ac196381cd2d947" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -1526,9 +1539,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" @@ -1571,13 +1584,12 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libredox" -version = "0.0.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "libc", - "redox_syscall", ] [[package]] @@ -1643,9 +1655,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "migration" @@ -1810,7 +1822,7 @@ version = "0.10.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "cfg-if", "foreign-types", "libc", @@ -1827,7 +1839,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -1838,9 +1850,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.101" +version = "0.9.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff" +checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" dependencies = [ "cc", "libc", @@ -1884,7 +1896,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -1939,9 +1951,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.8" +version = "2.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f8023d0fb78c8e03784ea1c7f3fa36e68a723138990b8d5a47d916b651e7a8" +checksum = "311fb059dee1a7b802f036316d790138c613a4e8b180c822e3925a662e9f0c95" dependencies = [ "memchr", "thiserror", @@ -1950,9 +1962,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.8" +version = "2.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0d24f72393fd16ab6ac5738bc33cdb6a9aa73f8b902e8fe29cf4e67d7dd1026" +checksum = "f73541b156d32197eecda1a4014d7f868fd2bcb3c550d5386087cfba442bf69c" dependencies = [ "pest", "pest_generator", @@ -1960,22 +1972,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.8" +version = "2.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc17e2a6c7d0a492f0158d7a4bd66cc17280308bbaff78d5bef566dca35ab80" +checksum = "c35eeed0a3fab112f75165fdc026b3913f4183133f19b49be773ac9ea966e8bd" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] name = "pest_meta" -version = "2.7.8" +version = "2.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "934cd7631c050f4674352a6e835d5f6711ffbfb9345c2fc0107155ac495ae293" +checksum = "2adbf29bb9776f28caece835398781ab24435585fe0d4dc1374a61db5accedca" dependencies = [ "once_cell", "pest", @@ -1999,14 +2011,14 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -2021,7 +2033,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" dependencies = [ "atomic-waker", - "fastrand 2.0.1", + "fastrand 2.0.2", "futures-io", ] @@ -2070,14 +2082,15 @@ dependencies = [ [[package]] name = "polling" -version = "3.5.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24f040dee2588b4963afb4e420540439d126f73fdacf4a9c486a96d840bac3c9" +checksum = "e0c976a60b2d7e99d6f229e414670a9b85d13ac305cc6d1e9c134de58c5aaaf6" dependencies = [ "cfg-if", "concurrent-queue", + "hermit-abi", "pin-project-lite", - "rustix 0.38.31", + "rustix 0.38.32", "tracing", "windows-sys 0.52.0", ] @@ -2238,9 +2251,9 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ "getrandom", "libredox", @@ -2249,14 +2262,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.3" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", "regex-automata 0.4.6", - "regex-syntax 0.8.2", + "regex-syntax 0.8.3", ] [[package]] @@ -2276,7 +2289,7 @@ checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax 0.8.3", ] [[package]] @@ -2287,9 +2300,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "rend" @@ -2302,9 +2315,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.0" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58b48d98d932f4ee75e541614d32a7f44c889b72bd9c2e04d95edd135989df88" +checksum = "2d66674f2b6fb864665eea7a3c1ac4e3dfacd2fda83cf6f935a612e01b0e3338" dependencies = [ "async-compression", "base64", @@ -2399,9 +2412,9 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.34.3" +version = "1.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39449a79f45e8da28c57c341891b69a183044b29518bb8f86dbac9df60bb7df" +checksum = "1790d1c4c0ca81211399e0e0af16333276f375209e71a37b67698a373db5b47a" dependencies = [ "arrayvec", "borsh", @@ -2435,11 +2448,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.31" +version = "0.38.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "errno", "libc", "linux-raw-sys 0.4.13", @@ -2492,7 +2505,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -2550,7 +2563,7 @@ dependencies = [ "proc-macro2", "quote", "sea-bae", - "syn 2.0.52", + "syn 2.0.58", "unicode-ident", ] @@ -2614,7 +2627,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", "thiserror", ] @@ -2649,9 +2662,9 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" [[package]] name = "security-framework" -version = "2.9.2" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -2662,9 +2675,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.1" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" dependencies = [ "core-foundation-sys", "libc", @@ -2687,14 +2700,14 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" dependencies = [ "itoa", "ryu", @@ -2789,9 +2802,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" @@ -2955,7 +2968,7 @@ dependencies = [ "atoi", "base64", "bigdecimal", - "bitflags 2.4.2", + "bitflags 2.5.0", "byteorder", "bytes", "chrono", @@ -3002,7 +3015,7 @@ dependencies = [ "atoi", "base64", "bigdecimal", - "bitflags 2.4.2", + "bitflags 2.5.0", "byteorder", "chrono", "crc", @@ -3082,9 +3095,9 @@ dependencies = [ [[package]] name = "strsim" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" @@ -3111,7 +3124,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -3133,9 +3146,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.52" +version = "2.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" dependencies = [ "proc-macro2", "quote", @@ -3151,7 +3164,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -3194,8 +3207,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", - "fastrand 2.0.1", - "rustix 0.38.31", + "fastrand 2.0.2", + "rustix 0.38.32", "windows-sys 0.52.0", ] @@ -3216,7 +3229,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -3277,9 +3290,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.36.0" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", "bytes", @@ -3302,7 +3315,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -3433,7 +3446,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -3609,7 +3622,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", "wasm-bindgen-shared", ] @@ -3643,7 +3656,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3904,7 +3917,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 639198d..3394169 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,8 @@ version = "2.0.0" edition = "2021" [dependencies] -anyhow = "1.0.81" +anyhow = { version = "1.0.81", features = ["backtrace"] } +arc-swap = { version = "1.7", features = ["serde"] } async-stream = "0.3.5" chrono = { version = "0.4.35", features = ["serde"] } cookie = "0.18.0" diff --git a/README.md b/README.md index 1c970a4..f6f675a 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,6 @@ > [!CAUTION] > 当前新版本尚不稳定,可能会有未告知的不兼容更改,请优先使用 Python 版本。 - 为 NAS 用户编写的 BILIBILI 收藏夹同步工具,可使用 EMBY 等媒体库工具浏览。 支持展示视频封面、名称、加入日期、标签、分页等。 @@ -34,14 +33,18 @@ video_name 支持设置 bvid(视频编号)、title(视频标题)、upper page_name 除支持 video 的全部参数外,还支持 ptitle(分 P 标题)、pid(分 P 页号)。 对于每个 favorite_list 的下载路径,程序会在其下建立如下的文件夹: + 1. 单页视频: + ```bash ├── {video_name} │   ├── {page_name}.mp4 │   ├── {page_name}.nfo │   └── {page_name}-poster.jpg ``` + 2. 多页视频: + ```bash ├── {video_name} │   ├── poster.jpg @@ -54,6 +57,7 @@ page_name 除支持 video 的全部参数外,还支持 ptitle(分 P 标题 │   │   └── {page_name} - S01E02-thumb.jpg │   └── tvshow.nfo ``` + 对于 filter_option 的可选值,请前往 [analyzer.rs](https://github.com/amtoaer/bili-sync/blob/main/src/bilibili/analyzer.rs) 查看。 ## 配置文件示例与说明 @@ -102,4 +106,4 @@ no_hires = false - [ ] 提供简单易用的打包(如 docker) - [ ] 更好的错误处理 - [ ] 更好的日志 -- [ ] 请求过快出现风控的 workaround \ No newline at end of file +- [ ] 请求过快出现风控的 workaround diff --git a/src/bilibili/client.rs b/src/bilibili/client.rs index 5a5a647..954ad45 100644 --- a/src/bilibili/client.rs +++ b/src/bilibili/client.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use anyhow::Result; use reqwest::{header, Method}; @@ -54,31 +56,30 @@ impl Default for Client { } pub struct BiliClient { - credential: Option, client: Client, } impl BiliClient { - pub fn new(credential: Option) -> Self { + pub fn new() -> Self { let client = Client::new(); - Self { credential, client } + Self { client } } pub fn request(&self, method: Method, url: &str) -> reqwest::RequestBuilder { - self.client.request(method, url, self.credential.as_ref()) + let credential = CONFIG.credential.load(); + self.client.request(method, url, credential.as_deref()) } - pub async fn check_refresh(&mut self) -> Result<()> { - let Some(credential) = self.credential.as_mut() else { + pub async fn check_refresh(&self) -> Result<()> { + let credential = CONFIG.credential.load(); + let Some(credential) = credential.as_deref() else { return Ok(()); }; if !credential.need_refresh(&self.client).await? { return Ok(()); } - credential.refresh(&self.client).await?; - - let mut config = CONFIG.lock().unwrap(); - config.credential = Some(credential.clone()); - config.save() + let new_credential = credential.refresh(&self.client).await?; + CONFIG.credential.store(Some(Arc::new(new_credential))); + CONFIG.save() } } diff --git a/src/bilibili/credential.rs b/src/bilibili/credential.rs index e86f958..f2fb33f 100644 --- a/src/bilibili/credential.rs +++ b/src/bilibili/credential.rs @@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize}; use super::error::BiliError; use crate::bilibili::Client; -#[derive(Default, Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct Credential { pub sessdata: String, pub bili_jct: String, @@ -32,6 +32,16 @@ impl Credential { } } + const fn empty() -> Self { + Self { + sessdata: String::new(), + bili_jct: String::new(), + buvid3: String::new(), + dedeuserid: String::new(), + ac_time_value: String::new(), + } + } + /// 检查凭据是否有效 pub async fn need_refresh(&self, client: &Client) -> Result { let res = client @@ -55,13 +65,12 @@ impl Credential { res["data"]["refresh"].as_bool().ok_or(anyhow!("check refresh failed")) } - pub async fn refresh(&mut self, client: &Client) -> Result<()> { + pub async fn refresh(&self, client: &Client) -> Result { let correspond_path = Self::get_correspond_path(); let csrf = self.get_refresh_csrf(client, correspond_path).await?; let new_credential = self.get_new_credential(client, &csrf).await?; self.confirm_refresh(client, &new_credential).await?; - *self = new_credential; - Ok(()) + Ok(new_credential) } fn get_correspond_path() -> String { @@ -125,9 +134,9 @@ JNrRuoEUXpabUzGB8QIDAQAB bail!(BiliError::RequestFailed(code, msg.to_owned())); } let set_cookies = headers.get_all(header::SET_COOKIE); - let mut credential = Credential { + let mut credential = Self { buvid3: self.buvid3.clone(), - ..Default::default() + ..Self::empty() }; let required_cookies = HashSet::from(["SESSDATA", "bili_jct", "DedeUserID"]); let cookies: Vec = set_cookies diff --git a/src/bilibili/favorite_list.rs b/src/bilibili/favorite_list.rs index dd69f44..1cc624d 100644 --- a/src/bilibili/favorite_list.rs +++ b/src/bilibili/favorite_list.rs @@ -3,7 +3,6 @@ use async_stream::stream; use chrono::serde::ts_seconds; use chrono::{DateTime, Utc}; use futures::Stream; -use log::error; use serde_json::Value; use crate::bilibili::error::BiliError; diff --git a/src/config.rs b/src/config.rs index 343dd96..1722e16 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,107 +1,114 @@ +use std::borrow::Cow; use std::collections::HashMap; -use std::path::Path; -use std::sync::Mutex; +use std::path::PathBuf; -use anyhow::{anyhow, Result}; -use log::warn; +use anyhow::Result; +use arc_swap::ArcSwapOption; use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; use crate::bilibili::{Credential, FilterOption}; -pub static CONFIG: Lazy> = Lazy::new(|| { - let config = Config::new(); - // 保存一次,确保配置文件存在 - config.save().unwrap(); +pub static CONFIG: Lazy = Lazy::new(|| { + let config = Config::load().unwrap_or_else(|err| { + warn!("Failed loading config: {err}"); + let new_config = Config::new(); + // 保存一次,确保配置文件存在 + new_config.save().unwrap(); + new_config + }); // 检查配置文件内容 config.check(); - Mutex::new(Config::new()) + config }); +pub static CONFIG_DIR: Lazy = + Lazy::new(|| dirs::config_dir().expect("No config path found").join("bili-sync")); + #[derive(Serialize, Deserialize)] pub struct Config { - pub credential: Option, + pub credential: ArcSwapOption, pub filter_option: FilterOption, - pub favorite_list: HashMap, - pub video_name: String, - pub page_name: String, + pub favorite_list: HashMap, + pub video_name: Cow<'static, str>, + pub page_name: Cow<'static, str>, pub interval: u64, - pub upper_path: String, + pub upper_path: PathBuf, } impl Default for Config { fn default() -> Self { - Self { - credential: Some(Credential::default()), - filter_option: FilterOption::default(), - favorite_list: HashMap::new(), - video_name: "{{bvid}}".to_string(), - page_name: "{{bvid}}".to_string(), - interval: 1200, - upper_path: dirs::config_dir() - .unwrap() - .join("bili-sync") - .join("upper_face") - .to_str() - .unwrap() - .to_string(), - } + Self::new() } } + impl Config { fn new() -> Self { - Config::load().unwrap_or_default() + Self { + credential: ArcSwapOption::empty(), + filter_option: FilterOption::default(), + favorite_list: HashMap::new(), + video_name: Cow::Borrowed("{{bvid}}"), + page_name: Cow::Borrowed("{{bvid}}"), + interval: 1200, + upper_path: CONFIG_DIR.join("upper_face"), + } } /// 简单的预检查 pub fn check(&self) { - assert!( - !self.favorite_list.is_empty(), - "No favorite list found, program won't do anything" - ); - for path in self.favorite_list.values() { - assert!(Path::new(path).is_absolute(), "Path in favorite list must be absolute"); + let mut ok = true; + if self.favorite_list.is_empty() { + ok = false; + error!("No favorite list found, program won't do anything"); } - assert!( - Path::new(&self.upper_path).is_absolute(), - "Upper face path must be absolute" - ); - assert!(!self.video_name.is_empty(), "No video name template found"); - assert!(!self.page_name.is_empty(), "No page name template found"); - match self.credential { - Some(ref credential) => { - assert!( - !(credential.sessdata.is_empty() - || credential.bili_jct.is_empty() - || credential.buvid3.is_empty() - || credential.dedeuserid.is_empty() - || credential.ac_time_value.is_empty()), - "Credential is incomplete" - ) + for path in self.favorite_list.values() { + if !path.is_absolute() { + ok = false; + error!("Path in favorite list must be absolute: {}", path.display()); } - None => { - warn!("No credential found, can't access high quality video"); + } + if !self.upper_path.is_absolute() { + ok = false; + error!("Upper face path must be absolute"); + } + if self.video_name.is_empty() { + ok = false; + error!("No video name template found"); + } + if self.page_name.is_empty() { + ok = false; + error!("No page name template found"); + } + let credential = self.credential.load(); + if let Some(credential) = credential.as_deref() { + if credential.sessdata.is_empty() + || credential.bili_jct.is_empty() + || credential.buvid3.is_empty() + || credential.dedeuserid.is_empty() + || credential.ac_time_value.is_empty() + { + ok = false; + error!("Credential is incomplete"); } + } else { + warn!("No credential found, can't access high quality video"); + } + + if !ok { + panic!("Config in {} is invalid", CONFIG_DIR.join("config.toml").display()); } } fn load() -> Result { - let config_path = dirs::config_dir() - .ok_or(anyhow!("No config path found"))? - .join("bili-sync") - .join("config.toml"); + let config_path = CONFIG_DIR.join("config.toml"); let config_content = std::fs::read_to_string(config_path)?; Ok(toml::from_str(&config_content)?) } pub fn save(&self) -> Result<()> { - let config_path = dirs::config_dir() - .ok_or(anyhow!("No config path found"))? - .join("bili-sync") - .join("config.toml"); - if let Some(parent) = config_path.parent() { - std::fs::create_dir_all(parent)?; - } + let config_path = CONFIG_DIR.join("config.toml"); + std::fs::create_dir_all(&*CONFIG_DIR)?; std::fs::write(config_path, toml::to_string_pretty(self)?)?; Ok(()) } diff --git a/src/core/command.rs b/src/core/command.rs index 6cd7e0a..0fdccf7 100644 --- a/src/core/command.rs +++ b/src/core/command.rs @@ -7,7 +7,6 @@ use entity::{favorite, page, video}; use filenamify::filenamify; use futures::stream::{FuturesOrdered, FuturesUnordered}; use futures::{pin_mut, Future, StreamExt}; -use log::{error, info, warn}; use sea_orm::entity::prelude::*; use sea_orm::ActiveValue::Set; use sea_orm::TransactionTrait; @@ -31,7 +30,7 @@ use crate::error::DownloadAbortError; pub async fn process_favorite_list( bili_client: &BiliClient, fid: &str, - path: &str, + path: &Path, connection: &DatabaseConnection, ) -> Result<()> { let favorite_model = refresh_favorite_list(bili_client, fid, path, connection).await?; @@ -43,7 +42,7 @@ pub async fn process_favorite_list( pub async fn refresh_favorite_list( bili_client: &BiliClient, fid: &str, - path: &str, + path: &Path, connection: &DatabaseConnection, ) -> Result { let bili_favorite_list = FavoriteList::new(bili_client, fid.to_owned()); @@ -141,11 +140,6 @@ pub async fn download_unprocessed_videos( for (video_model, _) in &unhandled_videos_pages { uppers_mutex.insert(video_model.upper_id, (Mutex::new(()), Mutex::new(()))); } - let upper_path = { - let config = CONFIG.lock().unwrap(); - config.upper_path.clone() - }; - let upper_path = Path::new(&upper_path); let mut tasks = unhandled_videos_pages .into_iter() .map(|(video_model, pages_model)| { @@ -157,7 +151,7 @@ pub async fn download_unprocessed_videos( connection, &semaphore, &downloader, - upper_path, + &CONFIG.upper_path, upper_mutex, ) }) diff --git a/src/core/utils.rs b/src/core/utils.rs index c0fda00..e4ad540 100644 --- a/src/core/utils.rs +++ b/src/core/utils.rs @@ -21,13 +21,10 @@ use crate::config::CONFIG; pub static TEMPLATE: Lazy = Lazy::new(|| { let mut handlebars = handlebars::Handlebars::new(); - let config = CONFIG.lock().unwrap(); handlebars - .register_template_string("video", config.video_name.clone()) - .unwrap(); - handlebars - .register_template_string("page", config.page_name.clone()) + .register_template_string("video", &CONFIG.video_name) .unwrap(); + handlebars.register_template_string("page", &CONFIG.page_name).unwrap(); handlebars }); @@ -48,13 +45,13 @@ pub struct NFOSerializer<'a>(pub ModelWrapper<'a>, pub NFOMode); /// 根据获得的收藏夹信息,插入或更新数据库中的收藏夹,并返回收藏夹对象 pub async fn handle_favorite_info( info: &FavoriteListInfo, - path: &str, + path: &Path, connection: &DatabaseConnection, ) -> Result { favorite::Entity::insert(favorite::ActiveModel { f_id: Set(info.id), - name: Set(info.title.to_string()), - path: Set(path.to_owned()), + name: Set(info.title.clone()), + path: Set(path.to_string_lossy().to_string()), ..Default::default() }) .on_conflict( diff --git a/src/database.rs b/src/database.rs index e05313a..b894273 100644 --- a/src/database.rs +++ b/src/database.rs @@ -1,18 +1,13 @@ -use anyhow::{anyhow, Result}; +use anyhow::Result; use migration::{Migrator, MigratorTrait}; use sea_orm::{Database, DatabaseConnection}; use tokio::fs; + +use crate::config::CONFIG_DIR; pub async fn database_connection() -> Result { - let config_dir = dirs::config_dir().ok_or(anyhow!("No config path found"))?; - let target = config_dir.join("bili-sync").join("data.sqlite"); - if let Some(parent) = target.parent() { - fs::create_dir_all(parent).await?; - } - Ok(Database::connect(format!( - "sqlite://{}?mode=rwc", - config_dir.join("bili-sync").join("data.sqlite").to_str().unwrap() - )) - .await?) + let target = CONFIG_DIR.join("data.sqlite"); + fs::create_dir_all(&*CONFIG_DIR).await?; + Ok(Database::connect(format!("sqlite://{}?mode=rwc", target.to_str().unwrap())).await?) } pub async fn migrate_database(connection: &DatabaseConnection) -> Result<()> { diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 594d15a..0000000 --- a/src/lib.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub mod bilibili; -pub mod config; -pub mod core; -pub mod database; -pub mod downloader; -pub mod error; diff --git a/src/main.rs b/src/main.rs index eeecdb2..76e8647 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,34 +1,44 @@ -use bili_sync::bilibili::BiliClient; -use bili_sync::core::command::process_favorite_list; -use bili_sync::database::{database_connection, migrate_database}; -use log::error; +#[macro_use] +extern crate log; + +mod bilibili; +mod config; +mod core; +mod database; +mod downloader; +mod error; + +use once_cell::sync::Lazy; + +use self::bilibili::BiliClient; +use self::config::CONFIG; +use self::core::command::process_favorite_list; +use self::database::{database_connection, migrate_database}; #[tokio::main] async fn main() -> ! { env_logger::init(); + Lazy::force(&CONFIG); let mut anchor = chrono::Local::now().date_naive(); - let (credential, interval, favorites) = { - let config = bili_sync::config::CONFIG.lock().unwrap(); - (config.credential.clone(), config.interval, config.favorite_list.clone()) - }; - let mut bili_client = BiliClient::new(credential); + let bili_client = BiliClient::new(); let connection = database_connection().await.unwrap(); migrate_database(&connection).await.unwrap(); loop { if anchor != chrono::Local::now().date_naive() { if let Err(e) = bili_client.check_refresh().await { error!("Error: {e}"); - tokio::time::sleep(std::time::Duration::from_secs(interval)).await; + tokio::time::sleep(std::time::Duration::from_secs(CONFIG.interval)).await; continue; } anchor = chrono::Local::now().date_naive(); } - for (fid, path) in &favorites { + for (fid, path) in &CONFIG.favorite_list { let res = process_favorite_list(&bili_client, fid, path, &connection).await; if let Err(e) = res { error!("Error: {e}"); } } - tokio::time::sleep(std::time::Duration::from_secs(interval)).await; + + tokio::time::sleep(std::time::Duration::from_secs(CONFIG.interval)).await; } }