diff --git a/Cargo.lock b/Cargo.lock index e10fdd3..301f2ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,23 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aligned-vec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" + [[package]] name = "anstream" version = "0.6.13" @@ -65,12 +82,64 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "anyhow" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" + +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" + +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + [[package]] name = "autocfg" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +[[package]] +name = "av1-grain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6678909d8c5d46a42abcf571271e15fdbc0a225e3646cf23762cd415046c78bf" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876c75a42f6364451a033496a14c44bffe41f5f4a8236f697391f11024e596d2" +dependencies = [ + "arrayvec", +] + [[package]] name = "backtrace" version = "0.3.71" @@ -92,6 +161,18 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + [[package]] name = "bitflags" version = "1.3.2" @@ -104,6 +185,12 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +[[package]] +name = "bitstream-io" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06c9989a51171e2e81038ab168b6ae22886fe9ded214430dbb4f41c28cf176da" + [[package]] name = "block-buffer" version = "0.10.4" @@ -113,12 +200,24 @@ dependencies = [ "generic-array", ] +[[package]] +name = "built" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d17f4d6e4dc36d1a02fbedc2753a096848e7c1b0772f7654eab8e2c927dd53" + [[package]] name = "bumpalo" version = "3.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" +[[package]] +name = "bytemuck" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" + [[package]] name = "byteorder" version = "1.5.0" @@ -157,6 +256,20 @@ name = "cc" version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +dependencies = [ + "jobserver", + "libc", +] + +[[package]] +name = "cfg-expr" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa50868b64a9a6fda9d593ce778849ea8715cd2a3d2cc17ffdb4a2f2f2f1961d" +dependencies = [ + "smallvec", + "target-lexicon", +] [[package]] name = "cfg-if" @@ -170,6 +283,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clap" version = "4.5.4" @@ -210,12 +333,24 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + [[package]] name = "colorchoice" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + [[package]] name = "core-foundation" version = "0.9.4" @@ -250,6 +385,62 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "crossterm" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" +dependencies = [ + "bitflags 2.5.0", + "crossterm_winapi", + "libc", + "mio", + "parking_lot", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-common" version = "0.1.6" @@ -270,6 +461,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + [[package]] name = "digest" version = "0.10.7" @@ -278,8 +478,36 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", + "subtle", ] +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + [[package]] name = "encoding_rs" version = "0.8.33" @@ -305,12 +533,37 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "exr" +version = "1.72.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "887d93f60543e9a9362ef8a21beedd0a833c5d9610e18c67abe15a5963dcb1a4" +dependencies = [ + "bit_field", + "flume", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + [[package]] name = "fastrand" version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" +[[package]] +name = "fdeflate" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" +dependencies = [ + "simd-adler32", +] + [[package]] name = "flate2" version = "1.0.28" @@ -321,6 +574,15 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "spin", +] + [[package]] name = "fnv" version = "1.0.7" @@ -417,7 +679,17 @@ checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", +] + +[[package]] +name = "gif" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" +dependencies = [ + "color_quant", + "weezl", ] [[package]] @@ -445,6 +717,16 @@ dependencies = [ "tracing", ] +[[package]] +name = "half" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5eceaaeec696539ddaf7b333340f1af35a5aa87ae3e4f3ead0532f72affab2e" +dependencies = [ + "cfg-if", + "crunchy", +] + [[package]] name = "hashbrown" version = "0.14.3" @@ -457,6 +739,15 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "http" version = "0.2.12" @@ -538,6 +829,45 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "image" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd54d660e773627692c524beaad361aca785a4f9f5730ce91f42aabe5bce3d11" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "exr", + "gif", + "image-webp", + "num-traits", + "png", + "qoi", + "ravif", + "rayon", + "rgb", + "tiff", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "image-webp" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a84a25dcae3ac487bc24ef280f9e20c79c9b1a3e5e32cbed3041d1c514aa87c" +dependencies = [ + "byteorder", + "thiserror", +] + +[[package]] +name = "imgref" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44feda355f4159a7c757171a77de25daf6411e217b4cabd03bd6650690468126" + [[package]] name = "indexmap" version = "2.2.6" @@ -548,18 +878,62 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "ipnet" version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "jobserver" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +dependencies = [ + "libc", +] + +[[package]] +name = "jpeg-decoder" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" + [[package]] name = "js-sys" version = "0.3.69" @@ -575,24 +949,80 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lebe" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" + [[package]] name = "libc" version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +[[package]] +name = "libfuzzer-sys" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7" +dependencies = [ + "arbitrary", + "cc", + "once_cell", +] + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.5.0", + "libc", +] + [[package]] name = "linux-raw-sys" version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + [[package]] name = "memchr" version = "2.7.2" @@ -605,6 +1035,12 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.7.2" @@ -612,6 +1048,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", + "simd-adler32", ] [[package]] @@ -621,7 +1058,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "log", + "wasi", "windows-sys 0.48.0", ] @@ -643,6 +1081,12 @@ dependencies = [ "tempfile", ] +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + [[package]] name = "nix" version = "0.28.0" @@ -655,6 +1099,80 @@ dependencies = [ "libc", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", +] + [[package]] name = "object" version = "0.32.2" @@ -714,6 +1232,64 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", + "hmac", + "password-hash", + "sha2", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -738,6 +1314,25 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +[[package]] +name = "png" +version = "0.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -753,6 +1348,40 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "profiling" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8021cf59c8ec9c432cfc2526ac6b8aa508ecaf29cd415f271b8406c1b851c3fd" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quote" version = "1.0.35" @@ -792,6 +1421,96 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rav1e" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" +dependencies = [ + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "once_cell", + "paste", + "profiling", + "rand", + "rand_chacha", + "simd_helpers", + "system-deps", + "thiserror", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc13288f5ab39e6d7c9d501759712e6969fcc9734220846fc9ed26cae2cc4234" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_users" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + [[package]] name = "reqwest" version = "0.11.27" @@ -832,6 +1551,15 @@ dependencies = [ "winreg", ] +[[package]] +name = "rgb" +version = "0.8.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05aaa8004b64fd573fc9d002f4e632d51ad4f026c2b5ba95fcb6c2f32c2c47d8" +dependencies = [ + "bytemuck", +] + [[package]] name = "rust-embed" version = "8.3.0" @@ -899,7 +1627,10 @@ name = "rustmon" version = "0.1.0" dependencies = [ "clap", + "crossterm", "ctrlc", + "dirs", + "image", "rand", "reqwest", "rust-embed", @@ -931,6 +1662,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "security-framework" version = "2.10.0" @@ -985,6 +1722,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -997,6 +1743,17 @@ dependencies = [ "serde", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha2" version = "0.10.8" @@ -1008,6 +1765,51 @@ dependencies = [ "digest", ] +[[package]] +name = "signal-hook" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" +dependencies = [ + "libc", + "mio", + "signal-hook", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + [[package]] name = "slab" version = "0.4.9" @@ -1017,6 +1819,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + [[package]] name = "socket2" version = "0.5.6" @@ -1027,12 +1835,27 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + [[package]] name = "strsim" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + [[package]] name = "syn" version = "2.0.57" @@ -1071,6 +1894,25 @@ dependencies = [ "libc", ] +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "target-lexicon" +version = "0.12.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" + [[package]] name = "tempfile" version = "3.10.1" @@ -1104,16 +1946,35 @@ dependencies = [ ] [[package]] -name = "time" -version = "0.1.45" +name = "tiff" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", + "flate2", + "jpeg-decoder", + "weezl", ] +[[package]] +name = "time" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + [[package]] name = "tinyvec" version = "1.6.0" @@ -1168,6 +2029,40 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tower-service" version = "0.3.2" @@ -1243,12 +2138,29 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "v_frame" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", +] + [[package]] name = "vcpkg" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "version-compare" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" + [[package]] name = "version_check" version = "0.9.4" @@ -1274,12 +2186,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1362,6 +2268,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "weezl" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" + [[package]] name = "winapi" version = "0.3.9" @@ -1525,6 +2437,15 @@ version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +[[package]] +name = "winnow" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.50.0" @@ -1537,14 +2458,73 @@ dependencies = [ [[package]] name = "zip" -version = "0.5.13" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ab48844d61251bb3835145c521d88aa4031d7139e8485990f60ca911fa0815" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" dependencies = [ + "aes", "byteorder", "bzip2", + "constant_time_eq", "crc32fast", + "crossbeam-utils", "flate2", - "thiserror", + "hmac", + "pbkdf2", + "sha1", "time", + "zstd", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.10+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "zune-jpeg" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec866b44a2a1fd6133d363f073ca1b179f438f99e7e5bfb1e33f7181facfe448" +dependencies = [ + "zune-core", ] diff --git a/Cargo.toml b/Cargo.toml index ac21652..d84f09b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,11 +5,12 @@ edition = "2021" [dependencies] clap = { version = "4.5.4", features = ["derive"] } - -# clap = "2.0.0" -rand = { version = "0.8.4", features = ["small_rng"] } -serde_json = "1.0" -rust-embed = "8.3.0" +crossterm = "0.27.0" ctrlc = "3.4.4" +dirs = "5.0.1" +image = "0.25.1" +rand = { version = "0.8.4", features = ["small_rng"] } reqwest = { version = "0.11", features = ["json", "blocking"] } -zip = "0.5" +rust-embed = "8.3.0" +serde_json = "1.0.115" +zip = "0.6.6" diff --git a/src/bin/clap.rs b/src/bin/clap.rs index 6bce98d..c73d331 100644 --- a/src/bin/clap.rs +++ b/src/bin/clap.rs @@ -9,7 +9,7 @@ struct Args { name: String, // big - /// Show a larger version of the sprite + /// Show a bigger version of the sprite #[arg(short, long, default_value_t = false)] big: bool, diff --git a/src/bin/fetch.rs b/src/bin/fetch.rs deleted file mode 100644 index d4dd87d..0000000 --- a/src/bin/fetch.rs +++ /dev/null @@ -1,90 +0,0 @@ -// this fetches the sprites and downloads to the user's local machine -// https://github.com/Vomitblood/pokesprite/archive/refs/heads/master.zip - -// TODO: pass in url as argument and use it -// for now, we use this as default -const TARGET_URL: &str = "https://github.com/Vomitblood/pokesprite/archive/refs/heads/master.zip"; -const WORKING_DIRECTORY: &str = "/tmp/rustmon/"; - -fn main() { - // // create a working directory for the program to use - // match create_working_directory() { - // Ok(_) => (), - // Err(e) => eprintln!("Error creating working directory: {}", e), - // } - - // match download_colorscripts_archive(TARGET_URL) { - // Ok(_) => (), - // Err(e) => eprintln!("Error downloading file: {}", e), - // } - - // TODO: extract here as default unless specified in flags - extract_colorscripts_archive(std::path::Path::new(WORKING_DIRECTORY)).unwrap(); -} - -fn create_working_directory() -> std::io::Result<()> { - println!("Creating working directory at {}...", WORKING_DIRECTORY); - std::fs::create_dir(WORKING_DIRECTORY)?; - return Ok(()); -} - -fn download_colorscripts_archive(target_url: &str) -> Result<(), Box> { - println!("Fetching colorscripts archive..."); - - let response = reqwest::blocking::get(target_url)?; - - let mut dest = std::fs::File::create(format!("{}colorscripts.zip", WORKING_DIRECTORY))?; - - let response_body = response.error_for_status()?.bytes()?; - std::io::copy(&mut response_body.as_ref(), &mut dest)?; - - println!("Downloaded pokesprite.zip"); - - return Ok(()); -} - -fn extract_colorscripts_archive(extract_location: &std::path::Path) -> zip::result::ZipResult<()> { - // let archive_file = std::fs::File::open(&archive_path)?; - let archive_file = std::fs::File::open(std::path::Path::new( - format!("{}colorscripts.zip", WORKING_DIRECTORY).as_str(), - ))?; - let mut archive = zip::read::ZipArchive::new(std::io::BufReader::new(archive_file))?; - - for i in 0..archive.len() { - let mut file = archive.by_index(i)?; - let file_path = std::path::Path::new(file.name()); - let parent_dir = file_path - .parent() - .and_then(std::path::Path::file_name) - .and_then(std::ffi::OsStr::to_str) - .unwrap_or(""); - - if (file - .name() - .starts_with("pokesprite-master/pokemon-gen8/regular/") - && parent_dir == "regular") - || (file - .name() - .starts_with("pokesprite-master/pokemon-gen8/shiny/") - && parent_dir == "shiny") - { - let file_name = file_path - .file_name() - .and_then(std::ffi::OsStr::to_str) - .unwrap_or(""); - - let outpath = extract_location.join(parent_dir).join(file_name); - - if !file.name().ends_with('/') { - if let Some(p) = outpath.parent() { - if !p.exists() { - std::fs::create_dir_all(&p)?; - } - } - let mut outfile = std::fs::File::create(&outpath)?; - std::io::copy(&mut file, &mut outfile)?; - } - } - } - Ok(()) -} diff --git a/src/constants.rs b/src/constants.rs new file mode 100644 index 0000000..eab4d6e --- /dev/null +++ b/src/constants.rs @@ -0,0 +1,4 @@ +pub const TARGET_URL: &str = + "https://github.com/Vomitblood/pokesprite/archive/refs/heads/master.zip"; +pub const WORKING_DIRECTORY: &str = "/tmp/rustmon/"; +pub const EXTRACT_DESTINATION: &str = "~/.local/share/rustmon/"; diff --git a/src/fetch.rs b/src/fetch.rs new file mode 100644 index 0000000..8275c44 --- /dev/null +++ b/src/fetch.rs @@ -0,0 +1,349 @@ +use image::GenericImageView; +use std::io::Write; + +pub fn fetch(extract_destination: &std::path::Path, silent: bool) { + // prep working directory + match create_working_directory() { + Ok(_) => (), + Err(e) => eprintln!("Error creating working directory: {}", e), + }; + + // download colorscripts archive + match download_colorscripts_archive(crate::constants::TARGET_URL) { + Ok(_) => (), + Err(e) => eprintln!("Error downloading colorscripts archive: {}", e), + }; + + // extract colorscripts archive + // now we have the raw images + match extract_colorscripts_archive() { + Ok(_) => (), + Err(e) => eprintln!("Error extracting colorscripts archive: {}", e), + }; + + // crop images to content + match crop_all_images_in_directory() { + Ok(_) => (), + Err(e) => eprintln!("Error cropping images: {}", e), + }; + + // convert images to unicode, both small and big + match convert_images_to_ascii(extract_destination, silent) { + Ok(_) => (), + Err(e) => eprintln!("Error converting images to ASCII: {}", e), + }; + + // cleanup + match cleanup() { + Ok(_) => (), + Err(e) => eprintln!("Error cleaning up: {}", e), + }; +} + +fn create_working_directory() -> std::io::Result<()> { + println!( + "Creating working directory at {}...", + &crate::constants::WORKING_DIRECTORY + ); + // create intermediate directories also + std::fs::create_dir(&crate::constants::WORKING_DIRECTORY)?; + println!("Created working directory"); + return Ok(()); +} + +fn download_colorscripts_archive(target_url: &str) -> Result<(), Box> { + println!("Fetching colorscripts archive..."); + + let response = reqwest::blocking::get(target_url)?; + + let mut dest = std::fs::File::create(format!( + "{}pokesprite.zip", + &crate::constants::WORKING_DIRECTORY + ))?; + + let response_body = response.error_for_status()?.bytes()?; + std::io::copy(&mut response_body.as_ref(), &mut dest)?; + + println!("Downloaded colorscripts archive"); + + return Ok(()); +} + +fn extract_colorscripts_archive() -> zip::result::ZipResult<()> { + println!("Extracting colorscripts archive..."); + + let archive_file = std::fs::File::open(std::path::Path::new( + format!("{}pokesprite.zip", &crate::constants::WORKING_DIRECTORY).as_str(), + ))?; + let mut archive = zip::read::ZipArchive::new(std::io::BufReader::new(archive_file))?; + + // iterate over every single file in the archive + for i in 0..archive.len() { + let mut file = archive.by_index(i)?; + let file_path = std::path::Path::new(file.name()); + + let parent_dir = file_path + .parent() + .and_then(std::path::Path::file_name) + .and_then(std::ffi::OsStr::to_str) + .unwrap_or(""); + + // check if the file is a in the correct directory that is NOT a directory + if (file + .name() + .starts_with("pokesprite-master/pokemon-gen8/regular/") + && parent_dir == "regular") + || (file + .name() + .starts_with("pokesprite-master/pokemon-gen8/shiny/") + && parent_dir == "shiny") + { + let file_name = file_path + .file_name() + .and_then(std::ffi::OsStr::to_str) + .unwrap(); + + let outpath = std::path::Path::new(&crate::constants::WORKING_DIRECTORY) + .join("raw_images") + .join(parent_dir) + .join(file_name); + + if !file.name().ends_with('/') { + if let Some(p) = outpath.parent() { + if !p.exists() { + std::fs::create_dir_all(&p)?; + } + } + let mut outfile = std::fs::File::create(&outpath)?; + std::io::copy(&mut file, &mut outfile)?; + }; + }; + } + + println!("Extracted colorscripts archive"); + + return Ok(()); +} + +fn crop_all_images_in_directory() -> std::io::Result<()> { + println!("Cropping images..."); + + // make sure the cropped_images directory exists + std::fs::create_dir_all( + std::path::Path::new(crate::constants::WORKING_DIRECTORY).join("cropped_images"), + )?; + + // do for both regular and shiny subdirectories + for subdirectory in ["regular", "shiny"].iter() { + let input_subdirectory_path = std::path::Path::new(crate::constants::WORKING_DIRECTORY) + .join("raw_images") + .join(subdirectory); + let output_subdirectory_path = std::path::Path::new(crate::constants::WORKING_DIRECTORY) + .join("cropped_images") + .join(subdirectory); + + std::fs::create_dir_all(&output_subdirectory_path)?; + + for entry in std::fs::read_dir(&input_subdirectory_path)? { + let entry = entry?; + let path = entry.path(); + + let output_path = output_subdirectory_path.join(path.file_name().unwrap()); + crop_to_content(&path, &output_path).unwrap(); + } + } + + println!("Cropped images"); + + return Ok(()); +} + +fn crop_to_content( + input_path: &std::path::Path, + output_path: &std::path::Path, +) -> image::ImageResult { + // load the image + let img = image::open(input_path)?; + + let (width, height) = img.dimensions(); + let mut min_x = width; + let mut min_y = height; + let mut max_x = 0; + let mut max_y = 0; + + for y in 0..height { + for x in 0..width { + let pixel = img.get_pixel(x, y); + if pixel[3] != 0 { + // if pixel is not transparent + if x < min_x { + min_x = x; + } + if y < min_y { + min_y = y; + } + if x > max_x { + max_x = x; + } + if y > max_y { + max_y = y; + } + } + } + } + + let cropped_width = max_x - min_x + 1; + let cropped_height = max_y - min_y + 1; + + let mut cropped_img: image::ImageBuffer, Vec> = + image::ImageBuffer::new(cropped_width, cropped_height); + + for y in 0..cropped_height { + for x in 0..cropped_width { + let pixel = img.get_pixel(x + min_x, y + min_y); + cropped_img.put_pixel(x, y, pixel); + } + } + + let cropped_img = image::DynamicImage::ImageRgba8(cropped_img); + + // write the cropped image + cropped_img.save(output_path)?; + + return Ok(cropped_img); +} + +fn convert_images_to_ascii( + output_directory_path: &std::path::Path, + silent: bool, +) -> std::io::Result<()> { + println!("Extract destination: {:?}", output_directory_path); + println!("Converting images to ASCII..."); + + std::fs::create_dir_all(output_directory_path)?; + + for size in ["small", "big"].iter() { + for subdirectory in ["regular", "shiny"].iter() { + let input_subdirectory_path = + std::path::PathBuf::from(crate::constants::WORKING_DIRECTORY) + .join("cropped_images") + .join(subdirectory); + let output_subdirectory_path = output_directory_path + .join("colorscripts") + .join(size) + .join(subdirectory); + + std::fs::create_dir_all(&output_subdirectory_path)?; + + for entry in std::fs::read_dir(&input_subdirectory_path)? { + let entry = entry?; + let path = entry.path(); + + if path.is_file() { + let img = image::open(&path).unwrap(); + let ascii_art = if *size == "small" { + convert_image_to_unicode_small(&img) + } else { + convert_image_to_unicode_big(&img) + }; + + // print for fun + if silent == false { + println!("{}", ascii_art); + }; + + let output_path = output_subdirectory_path.join(path.file_stem().unwrap()); + let mut file = std::fs::File::create(output_path)?; + file.write_all(ascii_art.as_bytes())?; + } + } + } + } + + println!("Converted images to ASCII"); + + return Ok(()); +} + +fn convert_image_to_unicode_small(img: &image::DynamicImage) -> String { + let mut unicode_sprite = String::new(); + let (width, height) = img.dimensions(); + + for y in (0..height).step_by(2) { + for x in 0..width { + let upper_pixel = img.get_pixel(x, y); + let lower_pixel = if y + 1 < height { + img.get_pixel(x, y + 1) + } else { + upper_pixel // Fallback to upper pixel if there's no lower pixel. + }; + + if upper_pixel[3] == 0 && lower_pixel[3] == 0 { + unicode_sprite.push(' '); + } else if upper_pixel[3] == 0 { + unicode_sprite.push_str(&get_color_escape_code(lower_pixel, false)); + unicode_sprite.push('▄'); + } else if lower_pixel[3] == 0 { + unicode_sprite.push_str(&get_color_escape_code(upper_pixel, false)); + unicode_sprite.push('▀'); + } else { + unicode_sprite.push_str(&get_color_escape_code(upper_pixel, false)); + unicode_sprite.push_str(&get_color_escape_code(lower_pixel, true)); + unicode_sprite.push('▀'); + } + unicode_sprite.push_str("\x1b[0m"); // Reset ANSI code after each character + } + unicode_sprite.push('\n'); // New line for each row, plus reset might be added here too if colors extend beyond. + } + + return unicode_sprite; +} + +fn convert_image_to_unicode_big(img: &image::DynamicImage) -> String { + let mut unicode_sprite = String::new(); + let (width, height) = img.dimensions(); + + for y in 0..height { + for x in 0..width { + let pixel = img.get_pixel(x, y); + + if pixel[3] == 0 { + unicode_sprite.push_str(" "); + } else { + unicode_sprite.push_str(&get_color_escape_code(pixel, false)); + unicode_sprite.push_str("██"); + } + } + unicode_sprite.push('\n'); + } + + return unicode_sprite; +} + +fn get_color_escape_code(pixel: image::Rgba, background: bool) -> String { + if pixel[3] == 0 { + return format!("{}", crossterm::style::ResetColor); + } + + let color = crossterm::style::Color::Rgb { + r: pixel[0], + g: pixel[1], + b: pixel[2], + }; + + if background { + format!("{}", crossterm::style::SetBackgroundColor(color)) + } else { + format!("{}", crossterm::style::SetForegroundColor(color)) + } +} + +fn cleanup() -> std::io::Result<()> { + println!("Cleaning up..."); + + std::fs::remove_dir_all(std::path::Path::new(crate::constants::WORKING_DIRECTORY))?; + + println!("Cleaned up"); + + return Ok(()); +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..0751bac --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,2 @@ +pub mod constants; +pub mod fetch; diff --git a/src/main.rs b/src/main.rs index cee0cf7..6fdeee3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,279 +1,99 @@ -use rand::Rng; +use clap::Parser; -// set global constants -#[derive(rust_embed::RustEmbed)] -#[folder = "colorscripts/"] -struct ColorScriptsDir; +/* +# Arguments -const POKEMON_JSON: &str = std::include_str!("../pokemon.json"); +## Fetch +- `fetch` - Fetch the latest colorscripts from the repository +- `silent` - Don't print colorscripts to the console when generating +- `extract_destination` - eXtract the colorscripts archive to a specified location -const REGULAR_SUBDIR: &str = "regular"; -const SHINY_SUBDIR: &str = "shiny"; +## Print +- `name` - Select pokemon by name +- `big` - Show a bigger version of the sprite +- `list` - Show a list of all pokemon names +- `no-title` - Do not display pokemon name +- `shiny` - Show the shiny version of the sprite +*/ -const LARGE_SUBDIR: &str = "large"; -const SMALL_SUBDIR: &str = "small"; +/// Pokemon Colorscripts written in Rust +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +struct Args { + // fetch + /// Fetch the latest colorscripts from the repository + #[arg(short, long, default_value_t = false)] + fetch: bool, -const SHINY_RATE: f64 = 1.0 / 128.0; + // silent + /// Don't print colorscripts to the console when generating + #[arg(long = "silent", default_value_t = false)] + silent: bool, -const GENERATIONS: [(&str, (u32, u32)); 8] = [ - ("1", (1, 151)), - ("2", (152, 251)), - ("3", (252, 386)), - ("4", (387, 493)), - ("5", (494, 649)), - ("6", (650, 721)), - ("7", (722, 809)), - ("8", (810, 898)), -]; + // extract destination + /// eXtract the colorscripts archive to a specified location + #[arg(short = 'x', long = "extract", default_value_t = String::from(""))] + extract_destination: String, + /* + // big + /// Show a bigger version of the sprite + #[arg(short, long, default_value_t = false)] + big: bool, -fn print_file(filepath: &str) -> std::io::Result<()> { - return ColorScriptsDir::get(filepath) - .map(|file| { - let content = std::str::from_utf8(file.data.as_ref()).unwrap(); - println!("{}", content); - }) - .ok_or(std::io::Error::new( - std::io::ErrorKind::NotFound, - "File not found", - )); -} + // list + /// Show a list of all pokemon names + #[arg(short, long, default_value_t = false)] + list: bool, -fn list_pokemon_names() { - let pokemon_json: serde_json::Value = serde_json::from_str(POKEMON_JSON).unwrap(); + // name + /// Select pokemon by name + #[arg(short = 'a', long, default_value_t = String::from(""))] + name: String, - let mut count = 0; + // no-title + // NOTE: clap will convert the kebab-case to snake_case + // very smart! + // ...but very annoying for beginners + /// Do not display pokemon name + #[arg(long, default_value_t = false)] + no_title: bool, - if let serde_json::Value::Array(array) = pokemon_json { - for pokemon in array { - if let Some(name) = pokemon.get("name") { - if let serde_json::Value::String(name_str) = name { - println!("{}", name_str); - count += 1; - } - } - } - } - - println!("-------------------"); - println!("Total: {} Pokémons", count); - println!("Use the --name flag to view a specific Pokémon"); - println!("Tip: Use `grep` to search for a specific Pokémon"); -} - -fn show_pokemon_by_name( - name: &str, - show_title: bool, + // shiny + /// Show the shiny version of the sprite + #[arg(short, long, default_value_t = false)] shiny: bool, - is_large: bool, - form: Option<&str>, -) -> std::io::Result<()> { - // set variables - let color_subdir = if shiny { SHINY_SUBDIR } else { REGULAR_SUBDIR }; - let size_subdir = if is_large { LARGE_SUBDIR } else { SMALL_SUBDIR }; - - let pokemon_json: serde_json::Value = serde_json::from_str(POKEMON_JSON)?; - - let pokemon_names: Vec<&str> = pokemon_json - .as_array() - .unwrap() - .iter() - .map(|pokemon| pokemon["name"].as_str().unwrap()) - .collect(); - - if !pokemon_names.contains(&name) { - println!("Invalid pokemon {}", name); - std::process::exit(1); - } - - let mut name = name.to_string(); - - if let Some(form) = form { - let forms: Vec<&str> = pokemon_json - .as_array() - .unwrap() - .iter() - .filter(|pokemon| pokemon["name"].as_str().unwrap() == name) - .flat_map(|pokemon| pokemon["forms"].as_array().unwrap().iter()) - .map(|form| form.as_str().unwrap()) - .collect(); - - let alternate_forms: Vec<&str> = - forms.iter().filter(|&f| *f != "regular").cloned().collect(); - - if alternate_forms.contains(&form) { - name.push_str(&format!("-{}", form)); - } else { - println!("Invalid form '{}' for pokemon {}", form, name); - if alternate_forms.is_empty() { - println!("No alternate forms available for {}", name); - } else { - println!("Available alternate forms are"); - for form in alternate_forms { - println!("- {}", form); - } - } - std::process::exit(1); - } - } - - if show_title { - if shiny { - println!("{} (shiny)", name); - } else { - println!("{}", name); - } - } - - // Construct the embedded file path - let file_path = format!("{}/{}/{}", size_subdir, color_subdir, name); - - // Use the adjusted function to print file contents from embedded resources - print_file(&file_path)?; - - return Ok(()); -} - -fn show_random_pokemon( - generations: &str, - show_title: bool, - shiny: bool, - is_large: bool, -) -> std::io::Result<()> { - let mut rng = rand::thread_rng(); - - let start_gen = if generations.is_empty() { - "1" - } else if generations.contains(",") { - let gens: Vec<&str> = generations.split(",").collect(); - let gen = gens[rng.gen_range(0..gens.len())]; - gen - } else if generations.contains("-") { - let gens: Vec<&str> = generations.split("-").collect(); - gens[0] - } else { - generations - }; - - let pokemon_json: serde_json::Value = serde_json::from_str(POKEMON_JSON)?; - let pokemon: Vec = pokemon_json - .as_array() - .unwrap() - .iter() - .map(|p| p["name"].as_str().unwrap().to_string()) - .collect(); - - let generations_map: std::collections::HashMap<_, _> = GENERATIONS.iter().cloned().collect(); - - if let Some((start_idx, end_idx)) = generations_map.get(start_gen) { - let random_idx = rng.gen_range(*start_idx..=*end_idx); - let random_pokemon = &pokemon[random_idx as usize - 1]; - let shiny = if !shiny { - rng.gen::() <= SHINY_RATE - } else { - shiny - }; - show_pokemon_by_name(random_pokemon, show_title, shiny, is_large, None)?; - } else { - println!("Invalid generation '{}'", generations); - std::process::exit(1); - } - - return Ok(()); -} - -#[cfg(target_os = "windows")] -fn pause() { - use std::io::{self, Read, Write}; - let mut stdout = io::stdout(); - let mut stdin = io::stdin(); - - stdout.write_all(b"Press any key to continue...").unwrap(); - stdout.flush().unwrap(); - stdin.read(&mut [0]).unwrap(); -} - -#[cfg(not(target_os = "windows"))] -fn pause() { - // do literally nothing + */ } fn main() { - let matches = clap::App::new("rustmon") - .about("CLI utility to print out unicode image of a pokemon in your shell") - .arg( - clap::Arg::with_name("list") - .short("l") - .long("list") - .help("Print list of all pokemon"), - ) - .arg( - clap::Arg::with_name("name") - .short("n") - .long("name") - .value_name("POKEMON NAME") - .help("Select pokemon by name. Generally spelled like in the games."), - ) - .arg( - clap::Arg::with_name("form") - .short("f") - .long("form") - .value_name("FORM") - .help("Show an alternate form of a pokemon"), - ) - .arg( - clap::Arg::with_name("no-title") - .long("no-title") - .help("Do not display pokemon name"), - ) - .arg( - clap::Arg::with_name("shiny") - .short("s") - .long("shiny") - .help("Show the shiny version of the pokemon instead"), - ) - .arg( - clap::Arg::with_name("big") - .short("b") - .long("big") - .help("Show a larger version of the sprite"), - ) - .arg( - clap::Arg::with_name("random") - .short("r") - .long("random") - .value_name("GENERATION") - .help("Show a random pokemon. This flag can optionally be followed by a generation number or range (1-8) to show random pokemon from a specific generation or range of generations. The generations can be provided as a continuous range (eg. 1-3) or as a list of generations (1,3,6)"), - ) - .after_help("P.S. Use the minimon command for a minimalistic version of this tool") - .get_matches(); + let args = argument_validation(); - if matches.is_present("list") { - list_pokemon_names(); - } else if matches.is_present("name") { - let name = matches.value_of("name").unwrap(); - let no_title = matches.is_present("no-title"); - let shiny = matches.is_present("shiny"); - let big = matches.is_present("big"); - let form = matches.value_of("form"); - show_pokemon_by_name(name, !no_title, shiny, big, form).unwrap(); - } else if matches.is_present("random") { - let random = matches.value_of("random").unwrap_or(""); - let no_title = matches.is_present("no-title"); - let shiny = matches.is_present("shiny"); - let big = matches.is_present("big"); - if matches.is_present("form") { - println!("--form flag unexpected with --random"); - std::process::exit(1); - } - show_random_pokemon(random, !no_title, shiny, big).unwrap(); + if args.fetch == true { + // get data directory + let data_directory = match dirs::data_dir() { + Some(dir) => dir.join("rustmon"), + None => { + println!("Data directory not found"); + std::process::exit(1); + } + }; + + // decicde whether to use the default data directory or the one specified by the user + // if the user specifies a directory, use that + let extract_destination = if args.extract_destination.is_empty() { + data_directory + } else { + std::path::PathBuf::from(&args.extract_destination) + }; + + rustmon::fetch::fetch(&extract_destination, args.silent); } else { - // show random pokemon by default with support for other flags - let no_title = matches.is_present("no-title"); - let shiny = matches.is_present("shiny"); - let big = matches.is_present("big"); - show_random_pokemon("", !no_title, shiny, big).unwrap(); + println!("print deez nuts"); } - - // pause the program before exiting only for windows - pause(); +} + +fn argument_validation() -> Args { + let args = Args::parse(); + + return args; } diff --git a/testing.py b/testing/testing.py similarity index 100% rename from testing.py rename to testing/testing.py diff --git a/testing.ts b/testing/testing.ts similarity index 100% rename from testing.ts rename to testing/testing.ts