diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 393034f..f082275 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -69,3 +69,4 @@ jobs: upload_url: ${{ needs.create_release.outputs.upload_url }} asset_path: target/release/spotify-dl.${{ matrix.target }} asset_name: spotify-dl.${{ matrix.target }} + asset_content_type: application/octet-stream diff --git a/.gitignore b/.gitignore index 6c6fd4a..f8d4e5d 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ target/ # These are backup files generated by rustfmt **/*.rs.bk + +.DS_Store diff --git a/Cargo.lock b/Cargo.lock index f1682f8..c466038 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -67,7 +67,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5915f52fe2cf65e83924d037b6c5290b7cee097c6b5c8700746e6168a343fd6b" dependencies = [ "alsa-sys", - "bitflags", + "bitflags 1.3.2", "libc", "nix", ] @@ -90,7 +90,7 @@ checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.96", ] [[package]] @@ -141,7 +141,7 @@ version = "0.59.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cexpr", "clang-sys", "lazy_static", @@ -154,12 +154,41 @@ dependencies = [ "shlex", ] +[[package]] +name = "bindgen" +version = "0.66.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" +dependencies = [ + "bitflags 2.4.2", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.48", + "which", +] + [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + [[package]] name = "block-buffer" version = "0.9.0" @@ -265,7 +294,7 @@ version = "2.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ - "bitflags", + "bitflags 1.3.2", "textwrap", "unicode-width", ] @@ -316,7 +345,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11894b20ebfe1ff903cbdc52259693389eea03b94918a2def2c30c3bf227ad88" dependencies = [ - "bitflags", + "bitflags 1.3.2", "coreaudio-sys", ] @@ -326,7 +355,7 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dff444d80630d7073077d38d40b4501fd518bd2b922c2a55edcc8b0f7be57e6" dependencies = [ - "bindgen", + "bindgen 0.59.2", ] [[package]] @@ -422,7 +451,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn", + "syn 1.0.96", ] [[package]] @@ -433,7 +462,7 @@ checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ "darling_core", "quote", - "syn", + "syn 1.0.96", ] [[package]] @@ -455,6 +484,12 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + [[package]] name = "encode_unicode" version = "0.3.6" @@ -473,6 +508,16 @@ dependencies = [ "termcolor", ] +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "fastrand" version = "1.7.0" @@ -579,7 +624,7 @@ checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.96", ] [[package]] @@ -670,7 +715,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cff78e5788be1e0ab65b04d306b2ed5092c815ec97ec70f4ebd5aee158aa55d" dependencies = [ "base64", - "bitflags", + "bitflags 1.3.2", "bytes", "headers-core", "http", @@ -722,6 +767,15 @@ dependencies = [ "digest 0.9.0", ] +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "hostname" version = "0.3.1" @@ -817,7 +871,7 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cb37ae5aa60d57c5f3412df1f3e5a48a978804f4a7e70700bb5f97e8f1a6331" dependencies = [ - "bitflags", + "bitflags 1.3.2", "byteorder", "flate2", ] @@ -960,9 +1014,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.126" +version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" [[package]] name = "libflac-sys" @@ -1186,6 +1240,12 @@ dependencies = [ "protobuf-codegen-pure", ] +[[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.7" @@ -1214,6 +1274,17 @@ dependencies = [ "libc", ] +[[package]] +name = "machine-uid" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958d2e0ee250103b08a70a5785ca5abcd077a47584b35087248a93758c699f29" +dependencies = [ + "bindgen 0.66.1", + "cc", + "winreg", +] + [[package]] name = "match_cfg" version = "0.1.0" @@ -1282,7 +1353,7 @@ dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.36.1", ] [[package]] @@ -1316,7 +1387,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" dependencies = [ - "bitflags", + "bitflags 1.3.2", "jni-sys", "ndk-sys", "num_enum", @@ -1354,7 +1425,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.96", ] [[package]] @@ -1372,7 +1443,7 @@ version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cc", "cfg-if", "libc", @@ -1409,7 +1480,7 @@ checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.96", ] [[package]] @@ -1460,7 +1531,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.96", ] [[package]] @@ -1584,6 +1655,16 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +[[package]] +name = "prettyplease" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" +dependencies = [ + "proc-macro2", + "syn 2.0.48", +] + [[package]] name = "priority-queue" version = "1.2.2" @@ -1613,7 +1694,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.96", "version_check", ] @@ -1630,9 +1711,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" dependencies = [ "unicode-ident", ] @@ -1664,9 +1745,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.18" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -1717,7 +1798,7 @@ version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1780,6 +1861,19 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.38.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" +dependencies = [ + "bitflags 2.4.2", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + [[package]] name = "ryu" version = "1.0.10" @@ -1824,7 +1918,7 @@ checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.96", ] [[package]] @@ -1916,7 +2010,7 @@ dependencies = [ [[package]] name = "spotify-dl" -version = "0.1.0" +version = "0.1.2" dependencies = [ "audiotags", "flac-bound", @@ -1924,6 +2018,7 @@ dependencies = [ "futures-state-stream", "indicatif", "librespot", + "machine-uid", "regex", "rpassword", "structopt", @@ -1963,7 +2058,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.96", ] [[package]] @@ -1983,6 +2078,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "synstructure" version = "0.12.6" @@ -1991,7 +2097,7 @@ checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.96", "unicode-xid", ] @@ -2054,7 +2160,7 @@ checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.96", ] [[package]] @@ -2109,7 +2215,7 @@ checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.96", ] [[package]] @@ -2250,7 +2356,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7141e445af09c8919f1d5f8a20dae0b20c3b57a45dee0d5823c6ed5d237f15a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "chrono", "rustc_version", ] @@ -2315,7 +2421,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn", + "syn 1.0.96", "wasm-bindgen-shared", ] @@ -2337,7 +2443,7 @@ checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.96", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2358,6 +2464,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + [[package]] name = "winapi" version = "0.3.9" @@ -2395,43 +2513,185 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", ] +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "zerocopy" version = "0.3.0" @@ -2449,6 +2709,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d498dbd1fd7beb83c86709ae1c33ca50942889473473d287d56ce4770a18edfb" dependencies = [ "proc-macro2", - "syn", + "syn 1.0.96", "synstructure", ] diff --git a/Cargo.toml b/Cargo.toml index 46ab953..f56864a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,10 @@ [package] name = "spotify-dl" -version = "0.1.0" -authors = ["Guillem Castro "] -edition = "2018" +version = "0.1.2" +authors = ["Guillem Castro ", "Schreifuchs "] +edition = "2021" +readme = "README.md" +licence = "MIT" #links = "FLAC" [dependencies] @@ -16,6 +18,7 @@ tokio = { version = "1.18.2", features = ["rt"] } flac-bound = { version = "0.3.0", default-features = false, features = ["libflac-noogg"] } audiotags = "0.2.7182" regex = "1.7.1" +machine-uid = "0.5.1" [package.metadata.deb] depends="libflac-dev" diff --git a/README.md b/README.md index be0e129..d11273b 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ brew install flac ## Usage ``` -spotify-dl 0.1.0 +spotify-dl 0.1.1 A commandline utility to download music directly from Spotify USAGE: @@ -36,17 +36,19 @@ USAGE: FLAGS: -h, --help Prints help information - -o, --ordered Download songs in the order they are in the playlist, prfixing the filename with the track number + -o, --ordered Prefixing the filename with its index in the playlist -V, --version Prints version information OPTIONS: + -c, --compression Setting the flac compression level from 0 (fastest, least compression) to + 8 (slowest, most compression). A value larger than 8 will be Treated as 8. + Default is 4. -d, --destination The directory where the songs will be downloaded [default: .] -p, --password Your Spotify password -u, --username Your Spotify username ARGS: - ... A list of Spotify URIs (songs, podcasts or playlists) -``` + ... A list of Spotify URIs (songs, podcasts or playlists)``` Songs and playlists must be passed as Spotify URIs or URLs (e.g. `spotify:track:123456789abcdefghABCDEF` for songs and `spotify:playlist:123456789abcdefghABCDEF` for playlists or `https://open.spotify.com/playlist/123456789abcdefghABCDEF?si=1234567890`). @@ -56,4 +58,4 @@ The usage of this software may infringe Spotify's ToS and/or your local legislat ## License -spotify-dl is licensed under the MIT license. See [LICENSE](LICENSE). +spotify-dl is lic:ewensed under the MIT license. See [LICENSE](LICENSE). diff --git a/src/file_sink.rs b/src/file_sink.rs index 8cfd812..8c9e033 100644 --- a/src/file_sink.rs +++ b/src/file_sink.rs @@ -1,37 +1,43 @@ use std::path::Path; use audiotags::{Tag, TagType}; -use librespot::{playback::{audio_backend::{Open, Sink, SinkError}, config::AudioFormat, decoder::AudioPacket, convert::Converter}}; +use librespot::playback::{ + audio_backend::{Open, Sink, SinkError}, + config::AudioFormat, + convert::Converter, + decoder::AudioPacket, +}; // extern crate flac_bound; -use flac_bound::{FlacEncoder}; +use flac_bound::FlacEncoder; use crate::TrackMetadata; pub struct FileSink { sink: String, content: Vec, - metadata: Option + metadata: Option, + compression: u32, } impl FileSink { pub fn add_metadata(&mut self, meta: TrackMetadata) { self.metadata = Some(meta); } + pub fn set_compression(&mut self, compression: u32) { + self.compression = compression; + } } impl Open for FileSink { fn open(path: Option, _audio_format: AudioFormat) -> Self { - if let Some(path) = path { - let file = path; - FileSink { - sink: file, - content: Vec::new(), - metadata: None - } - } else { - panic!(); + let file_path = path.unwrap_or_else(|| panic!()); + FileSink { + sink: file_path, + content: Vec::new(), + metadata: None, + compression: 4, } } } @@ -42,21 +48,33 @@ impl Sink for FileSink { } fn stop(&mut self) -> Result<(), SinkError> { - let mut encoder = FlacEncoder::new().unwrap().channels(2).bits_per_sample(16).compression_level(4).init_file(&self.sink).unwrap(); - encoder.process_interleaved(self.content.as_slice(), (self.content.len()/2) as u32).unwrap(); + let mut encoder = FlacEncoder::new() + .unwrap() + .channels(2) + .bits_per_sample(16) + .compression_level(*&self.compression) + .init_file(&self.sink) + .unwrap(); + encoder + .process_interleaved(self.content.as_slice(), (self.content.len() / 2) as u32) + .unwrap(); encoder.finish().unwrap(); match &self.metadata { Some(meta) => { - let mut tag = Tag::new().with_tag_type(TagType::Flac).read_from_path(Path::new(&self.sink)).unwrap(); + let mut tag = Tag::new() + .with_tag_type(TagType::Flac) + .read_from_path(Path::new(&self.sink)) + .unwrap(); tag.set_album_title(&meta.album); for artist in &meta.artists { tag.add_artist(artist); } tag.set_title(&meta.track_name); - tag.write_to_path(&self.sink).expect("Failed to write metadata"); - }, + tag.write_to_path(&self.sink) + .expect("Failed to write metadata"); + } None => (), } Ok(()) diff --git a/src/main.rs b/src/main.rs index 754c28c..2911c57 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ mod file_sink; extern crate rpassword; +use std::path::Path; use std::path::PathBuf; use librespot::core::config::SessionConfig; @@ -45,6 +46,13 @@ struct Opt { help = "Prefixing the filename with its index in the playlist" )] ordered: bool, + #[structopt( + short = "c", + long = "compression", + help = "Setting the flac compression level from 0 (fastest, least compression) to +8 (slowest, most compression). A value larger than 8 will be Treated as 8. Default is 4." + )] + compression: Option, } #[derive(Clone)] @@ -55,18 +63,31 @@ pub struct TrackMetadata { } async fn create_session(credentials: Credentials) -> Session { - let session_config = SessionConfig::default(); + let mut session_config = SessionConfig::default(); + session_config.device_id = machine_uid::get().unwrap(); let session = Session::connect(session_config, credentials, None) .await .unwrap(); session } +fn make_filename_compatible(filename: &str) -> String { + let invalid_chars = ['<', '>', ':', '\'', '"', '/', '\\', '|', '?', '*']; + let mut clean = String::new(); + for c in filename.chars() { + if !invalid_chars.contains(&c) && c.is_ascii() && !c.is_control() && c.len_utf8() == 1 { + clean.push(c); + } + } + clean +} + async fn download_tracks( session: &Session, destination: PathBuf, tracks: Vec, ordered: bool, + compression: Option, ) { let player_config = PlayerConfig::default(); let bar_style = ProgressStyle::default_bar() @@ -101,29 +122,55 @@ async fn download_tracks( .name; metadata.artists.push(artist_name.clone()); } + let full_track_name = format!("{} - {}", artist_name, metadata.track_name); + let full_track_name_clean = make_filename_compatible(full_track_name.as_str()); + //let filename = format!("{}.flac", full_track_name_clean); let filename: String; if ordered { - filename = format!("{:03} - {}.flac", i + 1, full_track_name); + filename = format!("{:03} - {}.flac", i + 1, full_track_name_clean); } else { - filename = format!("{}.flac", full_track_name); + filename = format!("{}.flac", full_track_name_clean); } let joined_path = destination.join(&filename); let path = joined_path.to_str().unwrap(); - bar.set_message(full_track_name.as_str()); - let mut file_sink = file_sink::FileSink::open( - Some(path.to_owned()), - librespot::playback::config::AudioFormat::S16, - ); - file_sink.add_metadata(metadata); - let (mut player, _) = - Player::new(player_config.clone(), session.clone(), None, move || { - Box::new(file_sink) - }); - player.load(*track, true, 0); - player.await_end_of_track().await; - player.stop(); - bar.inc(1); + bar.set_message(full_track_name_clean.as_str()); + + let file_name = Path::new(path).file_stem().unwrap().to_str().unwrap(); + + let path_parent = Path::new(path).parent().unwrap(); + let entries = path_parent.read_dir().unwrap(); + + let mut file_exists = false; + for entry in entries { + let entry = entry.unwrap(); + let entry_path = entry.path(); + let entry_file_name = entry_path.file_stem().unwrap().to_str().unwrap(); + if entry_file_name == file_name { + file_exists = true; + break; + } + } + + if !file_exists { + let mut file_sink = file_sink::FileSink::open( + Some(path.to_owned()), + librespot::playback::config::AudioFormat::S16, + ); + file_sink.add_metadata(metadata); + file_sink.set_compression(compression.unwrap_or(4)); + let (mut player, _) = + Player::new(player_config.clone(), session.clone(), None, move || { + Box::new(file_sink) + }); + player.load(*track, true, 0); + player.await_end_of_track().await; + player.stop(); + bar.inc(1); + } else { + // println!("File with the same name already exists, skipping: {}", path); + bar.inc(1); + } } bar.finish(); } @@ -184,6 +231,7 @@ async fn main() { PathBuf::from(opt.destination), tracks, opt.ordered, + opt.compression, ) .await; }