Rockbox open source high quality audio player as a Music Player Daemon
mpris rockbox mpd libadwaita audio rust zig deno
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: implement new rockbox music library manager

+1156 -2
+510 -1
Cargo.lock
··· 387 387 checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" 388 388 389 389 [[package]] 390 + name = "android-tzdata" 391 + version = "0.1.1" 392 + source = "registry+https://github.com/rust-lang/crates.io-index" 393 + checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" 394 + 395 + [[package]] 390 396 name = "android_system_properties" 391 397 version = "0.1.5" 392 398 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 679 685 ] 680 686 681 687 [[package]] 688 + name = "atoi" 689 + version = "2.0.0" 690 + source = "registry+https://github.com/rust-lang/crates.io-index" 691 + checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" 692 + dependencies = [ 693 + "num-traits", 694 + ] 695 + 696 + [[package]] 682 697 name = "atomic-waker" 683 698 version = "1.1.2" 684 699 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 753 768 ] 754 769 755 770 [[package]] 771 + name = "base-x" 772 + version = "0.2.11" 773 + source = "registry+https://github.com/rust-lang/crates.io-index" 774 + checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" 775 + 776 + [[package]] 756 777 name = "base16ct" 757 778 version = "0.2.0" 758 779 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 763 784 version = "0.5.1" 764 785 source = "registry+https://github.com/rust-lang/crates.io-index" 765 786 checksum = "022dfe9eb35f19ebbcb51e0b40a5ab759f46ad60cadf7297e0bd085afb50e076" 787 + 788 + [[package]] 789 + name = "base36" 790 + version = "0.0.1" 791 + source = "registry+https://github.com/rust-lang/crates.io-index" 792 + checksum = "b9c26bddc1271f7112e5ec797e8eeba6de2de211c1488e506b9500196dbf77c5" 793 + dependencies = [ 794 + "base-x", 795 + "failure", 796 + ] 766 797 767 798 [[package]] 768 799 name = "base64" ··· 1030 1061 source = "registry+https://github.com/rust-lang/crates.io-index" 1031 1062 checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" 1032 1063 dependencies = [ 1064 + "android-tzdata", 1065 + "iana-time-zone", 1066 + "js-sys", 1033 1067 "num-traits", 1034 1068 "serde", 1069 + "wasm-bindgen", 1070 + "windows-targets 0.52.6", 1035 1071 ] 1036 1072 1037 1073 [[package]] ··· 1188 1224 ] 1189 1225 1190 1226 [[package]] 1227 + name = "crc" 1228 + version = "3.2.1" 1229 + source = "registry+https://github.com/rust-lang/crates.io-index" 1230 + checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" 1231 + dependencies = [ 1232 + "crc-catalog", 1233 + ] 1234 + 1235 + [[package]] 1236 + name = "crc-catalog" 1237 + version = "2.4.0" 1238 + source = "registry+https://github.com/rust-lang/crates.io-index" 1239 + checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" 1240 + 1241 + [[package]] 1191 1242 name = "crc32fast" 1192 1243 version = "1.4.2" 1193 1244 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1225 1276 ] 1226 1277 1227 1278 [[package]] 1279 + name = "crossbeam-queue" 1280 + version = "0.3.11" 1281 + source = "registry+https://github.com/rust-lang/crates.io-index" 1282 + checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" 1283 + dependencies = [ 1284 + "crossbeam-utils", 1285 + ] 1286 + 1287 + [[package]] 1228 1288 name = "crossbeam-utils" 1229 1289 version = "0.8.20" 1230 1290 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1263 1323 ] 1264 1324 1265 1325 [[package]] 1326 + name = "cuid" 1327 + version = "1.3.3" 1328 + source = "registry+https://github.com/rust-lang/crates.io-index" 1329 + checksum = "d7fe01ebbba358b9af4850d1a2b16d45f765137398e34134643790f19dc935a0" 1330 + dependencies = [ 1331 + "base36", 1332 + "cuid-util", 1333 + "cuid2", 1334 + "hostname 0.4.0", 1335 + "num", 1336 + "once_cell", 1337 + "rand", 1338 + "uuid", 1339 + ] 1340 + 1341 + [[package]] 1342 + name = "cuid-util" 1343 + version = "0.1.1" 1344 + source = "registry+https://github.com/rust-lang/crates.io-index" 1345 + checksum = "1d59a706635108a7e8eaae7ec8e6154504fafa4a415ef38690d94fccea051757" 1346 + 1347 + [[package]] 1348 + name = "cuid2" 1349 + version = "0.1.3" 1350 + source = "registry+https://github.com/rust-lang/crates.io-index" 1351 + checksum = "50e281dc36864ea88fae2ec4e21eb280e8239487acb1ddc59b528b0afa7997bd" 1352 + dependencies = [ 1353 + "cuid-util", 1354 + "getrandom", 1355 + "num", 1356 + "rand", 1357 + "sha3", 1358 + ] 1359 + 1360 + [[package]] 1266 1361 name = "curve25519-dalek" 1267 1362 version = "4.1.3" 1268 1363 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2389 2484 ] 2390 2485 2391 2486 [[package]] 2487 + name = "dotenvy" 2488 + version = "0.15.7" 2489 + source = "registry+https://github.com/rust-lang/crates.io-index" 2490 + checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" 2491 + 2492 + [[package]] 2392 2493 name = "dprint-swc-ext" 2393 2494 version = "0.18.0" 2394 2495 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2505 2606 version = "1.13.0" 2506 2607 source = "registry+https://github.com/rust-lang/crates.io-index" 2507 2608 checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 2609 + dependencies = [ 2610 + "serde", 2611 + ] 2508 2612 2509 2613 [[package]] 2510 2614 name = "elliptic-curve" ··· 2607 2711 checksum = "31ae425815400e5ed474178a7a22e275a9687086a12ca63ec793ff292d8fdae8" 2608 2712 2609 2713 [[package]] 2714 + name = "etcetera" 2715 + version = "0.8.0" 2716 + source = "registry+https://github.com/rust-lang/crates.io-index" 2717 + checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" 2718 + dependencies = [ 2719 + "cfg-if", 2720 + "home", 2721 + "windows-sys 0.48.0", 2722 + ] 2723 + 2724 + [[package]] 2610 2725 name = "event-listener" 2611 2726 version = "5.3.1" 2612 2727 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2628 2743 ] 2629 2744 2630 2745 [[package]] 2746 + name = "failure" 2747 + version = "0.1.8" 2748 + source = "registry+https://github.com/rust-lang/crates.io-index" 2749 + checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" 2750 + dependencies = [ 2751 + "backtrace", 2752 + "failure_derive", 2753 + ] 2754 + 2755 + [[package]] 2756 + name = "failure_derive" 2757 + version = "0.1.8" 2758 + source = "registry+https://github.com/rust-lang/crates.io-index" 2759 + checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" 2760 + dependencies = [ 2761 + "proc-macro2", 2762 + "quote", 2763 + "syn 1.0.109", 2764 + "synstructure 0.12.6", 2765 + ] 2766 + 2767 + [[package]] 2631 2768 name = "fallible-iterator" 2632 2769 version = "0.3.0" 2633 2770 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2757 2894 ] 2758 2895 2759 2896 [[package]] 2897 + name = "flume" 2898 + version = "0.11.0" 2899 + source = "registry+https://github.com/rust-lang/crates.io-index" 2900 + checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" 2901 + dependencies = [ 2902 + "futures-core", 2903 + "futures-sink", 2904 + "spin", 2905 + ] 2906 + 2907 + [[package]] 2760 2908 name = "fnv" 2761 2909 version = "1.0.7" 2762 2910 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2891 3039 "futures-core", 2892 3040 "futures-task", 2893 3041 "futures-util", 3042 + ] 3043 + 3044 + [[package]] 3045 + name = "futures-intrusive" 3046 + version = "0.5.0" 3047 + source = "registry+https://github.com/rust-lang/crates.io-index" 3048 + checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" 3049 + dependencies = [ 3050 + "futures-core", 3051 + "lock_api", 3052 + "parking_lot", 2894 3053 ] 2895 3054 2896 3055 [[package]] ··· 3239 3398 ] 3240 3399 3241 3400 [[package]] 3401 + name = "hostname" 3402 + version = "0.4.0" 3403 + source = "registry+https://github.com/rust-lang/crates.io-index" 3404 + checksum = "f9c7c7c8ac16c798734b8a24560c1362120597c40d5e1459f09498f8f6c8f2ba" 3405 + dependencies = [ 3406 + "cfg-if", 3407 + "libc", 3408 + "windows", 3409 + ] 3410 + 3411 + [[package]] 3242 3412 name = "hstr" 3243 3413 version = "0.2.12" 3244 3414 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3417 3587 ] 3418 3588 3419 3589 [[package]] 3590 + name = "iana-time-zone" 3591 + version = "0.1.61" 3592 + source = "registry+https://github.com/rust-lang/crates.io-index" 3593 + checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" 3594 + dependencies = [ 3595 + "android_system_properties", 3596 + "core-foundation-sys", 3597 + "iana-time-zone-haiku", 3598 + "js-sys", 3599 + "wasm-bindgen", 3600 + "windows-core", 3601 + ] 3602 + 3603 + [[package]] 3604 + name = "iana-time-zone-haiku" 3605 + version = "0.1.2" 3606 + source = "registry+https://github.com/rust-lang/crates.io-index" 3607 + checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 3608 + dependencies = [ 3609 + "cc", 3610 + ] 3611 + 3612 + [[package]] 3420 3613 name = "ident_case" 3421 3614 version = "1.0.1" 3422 3615 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3983 4176 ] 3984 4177 3985 4178 [[package]] 4179 + name = "md5" 4180 + version = "0.7.0" 4181 + source = "registry+https://github.com/rust-lang/crates.io-index" 4182 + checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" 4183 + 4184 + [[package]] 3986 4185 name = "memchr" 3987 4186 version = "2.7.4" 3988 4187 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4278 4477 ] 4279 4478 4280 4479 [[package]] 4480 + name = "num" 4481 + version = "0.4.3" 4482 + source = "registry+https://github.com/rust-lang/crates.io-index" 4483 + checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" 4484 + dependencies = [ 4485 + "num-bigint", 4486 + "num-complex", 4487 + "num-integer", 4488 + "num-iter", 4489 + "num-rational", 4490 + "num-traits", 4491 + ] 4492 + 4493 + [[package]] 4281 4494 name = "num-bigint" 4282 4495 version = "0.4.6" 4283 4496 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4308 4521 ] 4309 4522 4310 4523 [[package]] 4524 + name = "num-complex" 4525 + version = "0.4.6" 4526 + source = "registry+https://github.com/rust-lang/crates.io-index" 4527 + checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" 4528 + dependencies = [ 4529 + "num-traits", 4530 + ] 4531 + 4532 + [[package]] 4311 4533 name = "num-conv" 4312 4534 version = "0.1.0" 4313 4535 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4334 4556 ] 4335 4557 4336 4558 [[package]] 4559 + name = "num-rational" 4560 + version = "0.4.2" 4561 + source = "registry+https://github.com/rust-lang/crates.io-index" 4562 + checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" 4563 + dependencies = [ 4564 + "num-bigint", 4565 + "num-integer", 4566 + "num-traits", 4567 + ] 4568 + 4569 + [[package]] 4337 4570 name = "num-traits" 4338 4571 version = "0.2.19" 4339 4572 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 5290 5523 source = "registry+https://github.com/rust-lang/crates.io-index" 5291 5524 checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" 5292 5525 dependencies = [ 5293 - "hostname", 5526 + "hostname 0.3.1", 5294 5527 "quick-error", 5295 5528 ] 5296 5529 ··· 5334 5567 dependencies = [ 5335 5568 "clap", 5336 5569 "owo-colors 4.1.0", 5570 + "rockbox-library", 5571 + "tokio", 5337 5572 ] 5338 5573 5339 5574 [[package]] ··· 5369 5604 "reqwest", 5370 5605 "rockbox-sys", 5371 5606 "serde", 5607 + "tokio", 5608 + ] 5609 + 5610 + [[package]] 5611 + name = "rockbox-library" 5612 + version = "0.1.0" 5613 + dependencies = [ 5614 + "anyhow", 5615 + "chrono", 5616 + "cuid", 5617 + "futures", 5618 + "md5", 5619 + "owo-colors 4.1.0", 5620 + "rockbox-sys", 5621 + "sqlx", 5372 5622 "tokio", 5373 5623 ] 5374 5624 ··· 5970 6220 version = "1.13.2" 5971 6221 source = "registry+https://github.com/rust-lang/crates.io-index" 5972 6222 checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 6223 + dependencies = [ 6224 + "serde", 6225 + ] 5973 6226 5974 6227 [[package]] 5975 6228 name = "smartstring" ··· 6016 6269 version = "0.9.8" 6017 6270 source = "registry+https://github.com/rust-lang/crates.io-index" 6018 6271 checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 6272 + dependencies = [ 6273 + "lock_api", 6274 + ] 6019 6275 6020 6276 [[package]] 6021 6277 name = "spirv" ··· 6037 6293 ] 6038 6294 6039 6295 [[package]] 6296 + name = "sqlformat" 6297 + version = "0.2.6" 6298 + source = "registry+https://github.com/rust-lang/crates.io-index" 6299 + checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" 6300 + dependencies = [ 6301 + "nom 7.1.3", 6302 + "unicode_categories", 6303 + ] 6304 + 6305 + [[package]] 6306 + name = "sqlx" 6307 + version = "0.8.2" 6308 + source = "registry+https://github.com/rust-lang/crates.io-index" 6309 + checksum = "93334716a037193fac19df402f8571269c84a00852f6a7066b5d2616dcd64d3e" 6310 + dependencies = [ 6311 + "sqlx-core", 6312 + "sqlx-macros", 6313 + "sqlx-mysql", 6314 + "sqlx-postgres", 6315 + "sqlx-sqlite", 6316 + ] 6317 + 6318 + [[package]] 6319 + name = "sqlx-core" 6320 + version = "0.8.2" 6321 + source = "registry+https://github.com/rust-lang/crates.io-index" 6322 + checksum = "d4d8060b456358185f7d50c55d9b5066ad956956fddec42ee2e8567134a8936e" 6323 + dependencies = [ 6324 + "atoi", 6325 + "byteorder", 6326 + "bytes", 6327 + "chrono", 6328 + "crc", 6329 + "crossbeam-queue", 6330 + "either", 6331 + "event-listener", 6332 + "futures-channel", 6333 + "futures-core", 6334 + "futures-intrusive", 6335 + "futures-io", 6336 + "futures-util", 6337 + "hashbrown 0.14.5", 6338 + "hashlink", 6339 + "hex", 6340 + "indexmap 2.5.0", 6341 + "log", 6342 + "memchr", 6343 + "once_cell", 6344 + "paste", 6345 + "percent-encoding", 6346 + "rustls", 6347 + "rustls-pemfile", 6348 + "serde", 6349 + "serde_json", 6350 + "sha2", 6351 + "smallvec", 6352 + "sqlformat", 6353 + "thiserror", 6354 + "tokio", 6355 + "tokio-stream", 6356 + "tracing", 6357 + "url", 6358 + "webpki-roots", 6359 + ] 6360 + 6361 + [[package]] 6362 + name = "sqlx-macros" 6363 + version = "0.8.2" 6364 + source = "registry+https://github.com/rust-lang/crates.io-index" 6365 + checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657" 6366 + dependencies = [ 6367 + "proc-macro2", 6368 + "quote", 6369 + "sqlx-core", 6370 + "sqlx-macros-core", 6371 + "syn 2.0.77", 6372 + ] 6373 + 6374 + [[package]] 6375 + name = "sqlx-macros-core" 6376 + version = "0.8.2" 6377 + source = "registry+https://github.com/rust-lang/crates.io-index" 6378 + checksum = "1804e8a7c7865599c9c79be146dc8a9fd8cc86935fa641d3ea58e5f0688abaa5" 6379 + dependencies = [ 6380 + "dotenvy", 6381 + "either", 6382 + "heck 0.5.0", 6383 + "hex", 6384 + "once_cell", 6385 + "proc-macro2", 6386 + "quote", 6387 + "serde", 6388 + "serde_json", 6389 + "sha2", 6390 + "sqlx-core", 6391 + "sqlx-mysql", 6392 + "sqlx-postgres", 6393 + "sqlx-sqlite", 6394 + "syn 2.0.77", 6395 + "tempfile", 6396 + "tokio", 6397 + "url", 6398 + ] 6399 + 6400 + [[package]] 6401 + name = "sqlx-mysql" 6402 + version = "0.8.2" 6403 + source = "registry+https://github.com/rust-lang/crates.io-index" 6404 + checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a" 6405 + dependencies = [ 6406 + "atoi", 6407 + "base64 0.22.1", 6408 + "bitflags 2.6.0", 6409 + "byteorder", 6410 + "bytes", 6411 + "chrono", 6412 + "crc", 6413 + "digest", 6414 + "dotenvy", 6415 + "either", 6416 + "futures-channel", 6417 + "futures-core", 6418 + "futures-io", 6419 + "futures-util", 6420 + "generic-array", 6421 + "hex", 6422 + "hkdf", 6423 + "hmac", 6424 + "itoa", 6425 + "log", 6426 + "md-5", 6427 + "memchr", 6428 + "once_cell", 6429 + "percent-encoding", 6430 + "rand", 6431 + "rsa", 6432 + "serde", 6433 + "sha1", 6434 + "sha2", 6435 + "smallvec", 6436 + "sqlx-core", 6437 + "stringprep", 6438 + "thiserror", 6439 + "tracing", 6440 + "whoami", 6441 + ] 6442 + 6443 + [[package]] 6444 + name = "sqlx-postgres" 6445 + version = "0.8.2" 6446 + source = "registry+https://github.com/rust-lang/crates.io-index" 6447 + checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8" 6448 + dependencies = [ 6449 + "atoi", 6450 + "base64 0.22.1", 6451 + "bitflags 2.6.0", 6452 + "byteorder", 6453 + "chrono", 6454 + "crc", 6455 + "dotenvy", 6456 + "etcetera", 6457 + "futures-channel", 6458 + "futures-core", 6459 + "futures-io", 6460 + "futures-util", 6461 + "hex", 6462 + "hkdf", 6463 + "hmac", 6464 + "home", 6465 + "itoa", 6466 + "log", 6467 + "md-5", 6468 + "memchr", 6469 + "once_cell", 6470 + "rand", 6471 + "serde", 6472 + "serde_json", 6473 + "sha2", 6474 + "smallvec", 6475 + "sqlx-core", 6476 + "stringprep", 6477 + "thiserror", 6478 + "tracing", 6479 + "whoami", 6480 + ] 6481 + 6482 + [[package]] 6483 + name = "sqlx-sqlite" 6484 + version = "0.8.2" 6485 + source = "registry+https://github.com/rust-lang/crates.io-index" 6486 + checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680" 6487 + dependencies = [ 6488 + "atoi", 6489 + "chrono", 6490 + "flume", 6491 + "futures-channel", 6492 + "futures-core", 6493 + "futures-executor", 6494 + "futures-intrusive", 6495 + "futures-util", 6496 + "libsqlite3-sys", 6497 + "log", 6498 + "percent-encoding", 6499 + "serde", 6500 + "serde_urlencoded", 6501 + "sqlx-core", 6502 + "tracing", 6503 + "url", 6504 + ] 6505 + 6506 + [[package]] 6040 6507 name = "stable_deref_trait" 6041 6508 version = "1.2.0" 6042 6509 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 6077 6544 "quote", 6078 6545 "swc_macros_common", 6079 6546 "syn 2.0.77", 6547 + ] 6548 + 6549 + [[package]] 6550 + name = "stringprep" 6551 + version = "0.1.5" 6552 + source = "registry+https://github.com/rust-lang/crates.io-index" 6553 + checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" 6554 + dependencies = [ 6555 + "unicode-bidi", 6556 + "unicode-normalization", 6557 + "unicode-properties", 6080 6558 ] 6081 6559 6082 6560 [[package]] ··· 7102 7580 ] 7103 7581 7104 7582 [[package]] 7583 + name = "unicode-properties" 7584 + version = "0.1.2" 7585 + source = "registry+https://github.com/rust-lang/crates.io-index" 7586 + checksum = "52ea75f83c0137a9b98608359a5f1af8144876eb67bcb1ce837368e906a9f524" 7587 + 7588 + [[package]] 7105 7589 name = "unicode-segmentation" 7106 7590 version = "1.12.0" 7107 7591 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 7118 7602 version = "0.2.5" 7119 7603 source = "registry+https://github.com/rust-lang/crates.io-index" 7120 7604 checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" 7605 + 7606 + [[package]] 7607 + name = "unicode_categories" 7608 + version = "0.1.1" 7609 + source = "registry+https://github.com/rust-lang/crates.io-index" 7610 + checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" 7121 7611 7122 7612 [[package]] 7123 7613 name = "universal-hash" ··· 7514 8004 version = "0.4.0" 7515 8005 source = "registry+https://github.com/rust-lang/crates.io-index" 7516 8006 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 8007 + 8008 + [[package]] 8009 + name = "windows" 8010 + version = "0.52.0" 8011 + source = "registry+https://github.com/rust-lang/crates.io-index" 8012 + checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" 8013 + dependencies = [ 8014 + "windows-core", 8015 + "windows-targets 0.52.6", 8016 + ] 8017 + 8018 + [[package]] 8019 + name = "windows-core" 8020 + version = "0.52.0" 8021 + source = "registry+https://github.com/rust-lang/crates.io-index" 8022 + checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" 8023 + dependencies = [ 8024 + "windows-targets 0.52.6", 8025 + ] 7517 8026 7518 8027 [[package]] 7519 8028 name = "windows-registry"
+2
crates/cli/Cargo.toml
··· 9 9 [dependencies] 10 10 clap = "4.5.17" 11 11 owo-colors = "4.1.0" 12 + rockbox-library = {path = "../library"} 13 + tokio = {version = "1.36.0", features = ["full"]}
+15 -1
crates/cli/src/lib.rs
··· 1 1 use clap::Command; 2 2 use owo_colors::OwoColorize; 3 - use std::ffi::CStr; 3 + use rockbox_library::audio_scan::scan_audio_files; 4 + use rockbox_library::create_connection_pool; 5 + use std::thread; 6 + use std::{env, ffi::CStr}; 4 7 5 8 #[macro_export] 6 9 macro_rules! cast_ptr { ··· 46 49 let cli = Command::new("rockbox").version(VERSION).about(&banner); 47 50 48 51 cli.get_matches_from(args); 52 + 53 + thread::spawn(move || { 54 + let home = env::var("HOME").unwrap(); 55 + let path = env::var("ROCKBOX_LIBRARY").unwrap_or(format!("{}/Music", home)); 56 + let rt = tokio::runtime::Runtime::new().unwrap(); 57 + rt.block_on(async { 58 + let pool = create_connection_pool().await?; 59 + scan_audio_files(pool, path.into()).await 60 + }) 61 + .unwrap(); 62 + }); 49 63 50 64 return 0; 51 65 }
+15
crates/library/Cargo.toml
··· 1 + [package] 2 + edition = "2021" 3 + name = "rockbox-library" 4 + version = "0.1.0" 5 + 6 + [dependencies] 7 + anyhow = "1.0.89" 8 + chrono = "0.4.38" 9 + cuid = "1.3.3" 10 + futures = "0.3.30" 11 + md5 = "0.7.0" 12 + owo-colors = "4.1.0" 13 + rockbox-sys = {path = "../sys"} 14 + sqlx = {version = "0.8.2", features = ["runtime-tokio", "tls-rustls", "sqlite", "chrono", "derive", "macros"]} 15 + tokio = {version = "1.36.0", features = ["full"]}
+93
crates/library/migrations/20240923093823_create_tables.sql
··· 1 + -- Add migration script here 2 + CREATE TABLE IF NOT EXISTS album ( 3 + id VARCHAR(255) PRIMARY KEY, 4 + title VARCHAR(255) NOT NULL, 5 + artist VARCHAR(255) NOT NULL, 6 + year INT, 7 + year_string VARCHAR(255), 8 + album_art VARCHAR(255), 9 + md5 VARCHAR(255) NOT NULL UNIQUE 10 + ); 11 + 12 + CREATE TABLE IF NOT EXISTS track ( 13 + id VARCHAR(255) PRIMARY KEY, 14 + path VARCHAR(255) NOT NULL UNIQUE, 15 + title VARCHAR(255) NOT NULL, 16 + artist VARCHAR(255) NOT NULL, 17 + album VARCHAR(255) NOT NULL, 18 + album_artist VARCHAR(255) NOT NULL, 19 + bitrate INT NOT NULL, 20 + composer VARCHAR(255) NOT NULL, 21 + disc_number INT NOT NULL, 22 + filesize INT NOT NULL, 23 + frequency INT NOT NULL, 24 + length INT NOT NULL, 25 + track_number INT, 26 + year INT, 27 + year_string VARCHAR(255), 28 + genre VARCHAR(255), 29 + md5 VARCHAR(255) NOT NULL UNIQUE, 30 + album_art VARCHAR(255), 31 + artist_id VARCHAR(255) NOT NULL, 32 + album_id VARCHAR(255) NOT NULL, 33 + genre_id VARCHAR(255), 34 + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, 35 + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP 36 + ); 37 + 38 + CREATE TABLE IF NOT EXISTS artist ( 39 + id VARCHAR(255) PRIMARY KEY, 40 + name VARCHAR(255) NOT NULL UNIQUE, 41 + bio TEXT, 42 + image VARCHAR(255) 43 + ); 44 + 45 + CREATE TABLE IF NOT EXISTS genre ( 46 + id VARCHAR(255) PRIMARY KEY, 47 + name VARCHAR(255) NOT NULL, 48 + description TEXT, 49 + image VARCHAR(255) 50 + ); 51 + 52 + CREATE TABLE IF NOT EXISTS playlist ( 53 + id VARCHAR(255) PRIMARY KEY, 54 + name VARCHAR(255) NOT NULL, 55 + description TEXT, 56 + image VARCHAR(255), 57 + folder_id VARCHAR(255), 58 + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, 59 + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP 60 + ); 61 + 62 + CREATE TABLE IF NOT EXISTS playlist_tracks ( 63 + id VARCHAR(255) PRIMARY KEY, 64 + playlist_id VARCHAR(255) NOT NULL, 65 + track_id VARCHAR(255) NOT NULL, 66 + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP 67 + ); 68 + 69 + CREATE TABLE IF NOT EXISTS folder ( 70 + id VARCHAR(255) PRIMARY KEY, 71 + name VARCHAR(255) NOT NULL, 72 + parent_id VARCHAR(255), 73 + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, 74 + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP 75 + ); 76 + 77 + CREATE TABLE IF NOT EXISTS favourites ( 78 + id VARCHAR(255) PRIMARY KEY, 79 + track_id VARCHAR(255) NOT NULL, 80 + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP 81 + ); 82 + 83 + CREATE TABLE IF NOT EXISTS artist_tracks ( 84 + id VARCHAR(255) PRIMARY KEY, 85 + artist_id VARCHAR(255) NOT NULL, 86 + track_id VARCHAR(255) NOT NULL 87 + ); 88 + 89 + CREATE TABLE IF NOT EXISTS album_tracks ( 90 + id VARCHAR(255) PRIMARY KEY, 91 + album_id VARCHAR(255) NOT NULL, 92 + track_id VARCHAR(255) NOT NULL 93 + );
+132
crates/library/src/audio_scan.rs
··· 1 + use crate::entity::album::Album; 2 + use crate::entity::artist::Artist; 3 + use crate::{entity::track::Track, repo}; 4 + use anyhow::Error; 5 + use futures::future::BoxFuture; 6 + use futures::stream::{FuturesUnordered, StreamExt}; 7 + use owo_colors::OwoColorize; 8 + use rockbox_sys as rb; 9 + use sqlx::{Pool, Sqlite}; 10 + use std::path::PathBuf; 11 + use tokio::fs; 12 + 13 + const AUDIO_EXTENSIONS: [&str; 17] = [ 14 + "mp3", "ogg", "flac", "m4a", "aac", "mp4", "alac", "wav", "wv", "mpc", "aiff", "ac3", "opus", 15 + "spx", "sid", "ape", "wma", 16 + ]; 17 + 18 + pub fn scan_audio_files( 19 + pool: Pool<Sqlite>, 20 + audio_dir: PathBuf, 21 + ) -> BoxFuture<'static, Result<Vec<PathBuf>, Error>> { 22 + Box::pin(async move { 23 + let mut result = Vec::new(); 24 + let mut dir = fs::read_dir(audio_dir).await?; 25 + let mut futures = FuturesUnordered::new(); 26 + while let Some(entry) = dir.next_entry().await? { 27 + let path = entry.path(); 28 + if path.is_dir() { 29 + println!("{} {:?}", "Scanning".bright_green(), path); 30 + let dir_path = path.clone(); 31 + let cloned_pool = pool.clone(); 32 + futures.push(tokio::spawn(async move { 33 + scan_audio_files(cloned_pool, dir_path).await 34 + })); 35 + } else if path.is_file() { 36 + let path = path.to_str().unwrap(); 37 + if !AUDIO_EXTENSIONS 38 + .into_iter() 39 + .any(|ext| path.ends_with(&format!(".{}", ext))) 40 + { 41 + continue; 42 + } 43 + let filename = path.split('/').last().unwrap(); 44 + let dir = path.replace(filename, ""); 45 + println!( 46 + "{} {}{}", 47 + "Found".bright_green(), 48 + dir, 49 + filename.bright_yellow() 50 + ); 51 + let entry = rb::metadata::get_metadata(-1, path); 52 + 53 + let track_hash = format!("{:?}", md5::compute(entry.path.as_bytes())); 54 + let artist_id = cuid::cuid1()?; 55 + let album_id = cuid::cuid1()?; 56 + let album_md5 = format!( 57 + "{:?}", 58 + md5::compute(format!("{}{}", entry.albumartist, entry.album).as_bytes()) 59 + ); 60 + 61 + repo::track::save( 62 + pool.clone(), 63 + Track { 64 + id: cuid::cuid1()?, 65 + path: entry.path, 66 + title: entry.title, 67 + artist: entry.artist.clone(), 68 + album: entry.album.clone(), 69 + genre: match entry.genre_string.as_str() { 70 + "" => None, 71 + _ => Some(entry.genre_string), 72 + }, 73 + year: Some(entry.year as u32), 74 + track_number: Some(entry.tracknum as u32), 75 + disc_number: entry.discnum as u32, 76 + year_string: Some(entry.year_string.clone()), 77 + composer: entry.composer, 78 + album_artist: entry.albumartist.clone(), 79 + bitrate: entry.bitrate, 80 + frequency: entry.frequency as u32, 81 + filesize: entry.filesize as u32, 82 + length: entry.length as u32, 83 + md5: track_hash, 84 + created_at: chrono::Utc::now().timestamp_nanos_opt().unwrap() as i32, 85 + updated_at: chrono::Utc::now().timestamp_nanos_opt().unwrap() as i32, 86 + artist_id: artist_id.clone(), 87 + album_id: album_id.clone(), 88 + ..Default::default() 89 + }, 90 + ) 91 + .await?; 92 + 93 + repo::album::save( 94 + pool.clone(), 95 + Album { 96 + id: album_id, 97 + title: entry.album, 98 + artist: entry.albumartist.clone(), 99 + year: entry.year as u32, 100 + year_string: entry.year_string, 101 + album_art: None, 102 + md5: album_md5, 103 + }, 104 + ) 105 + .await?; 106 + 107 + repo::artist::save( 108 + pool.clone(), 109 + Artist { 110 + id: artist_id, 111 + name: entry.albumartist.clone(), 112 + bio: None, 113 + image: None, 114 + }, 115 + ) 116 + .await?; 117 + 118 + let path = path.into(); 119 + result.push(path); 120 + } 121 + } 122 + 123 + while let Some(Ok(sub_result)) = futures.next().await { 124 + match sub_result { 125 + Ok(paths) => result.extend(paths), 126 + Err(e) => return Err(e), 127 + } 128 + } 129 + 130 + Ok(result) 131 + }) 132 + }
+10
crates/library/src/entity/album.rs
··· 1 + #[derive(sqlx::FromRow, Default)] 2 + pub struct Album { 3 + pub id: String, 4 + pub title: String, 5 + pub artist: String, 6 + pub year: u32, 7 + pub year_string: String, 8 + pub album_art: Option<String>, 9 + pub md5: String, 10 + }
+6
crates/library/src/entity/album_tracks.rs
··· 1 + #[derive(sqlx::FromRow, Default)] 2 + pub struct AlbumTracks { 3 + pub id: String, 4 + pub album_id: String, 5 + pub track_id: String, 6 + }
+7
crates/library/src/entity/artist.rs
··· 1 + #[derive(sqlx::FromRow, Default)] 2 + pub struct Artist { 3 + pub id: String, 4 + pub name: String, 5 + pub bio: Option<String>, 6 + pub image: Option<String>, 7 + }
+6
crates/library/src/entity/artist_tracks.rs
··· 1 + #[derive(sqlx::FromRow, Default)] 2 + pub struct ArtistTracks { 3 + pub id: String, 4 + pub artist_id: String, 5 + pub track_id: String, 6 + }
+6
crates/library/src/entity/favourites.rs
··· 1 + #[derive(sqlx::FromRow, Default)] 2 + pub struct Favourites { 3 + pub id: String, 4 + pub track_id: String, 5 + pub created_at: i64, 6 + }
+6
crates/library/src/entity/folder.rs
··· 1 + #[derive(sqlx::FromRow, Default)] 2 + pub struct Folder { 3 + pub id: String, 4 + pub name: String, 5 + pub parent_id: Option<String>, 6 + }
+7
crates/library/src/entity/genre.rs
··· 1 + #[derive(sqlx::FromRow, Default)] 2 + pub struct Genre { 3 + pub id: String, 4 + pub name: String, 5 + pub description: Option<String>, 6 + pub image: Option<String>, 7 + }
+10
crates/library/src/entity/mod.rs
··· 1 + pub mod album; 2 + pub mod album_tracks; 3 + pub mod artist; 4 + pub mod artist_tracks; 5 + pub mod favourites; 6 + pub mod folder; 7 + pub mod genre; 8 + pub mod playlist; 9 + pub mod playlist_tracks; 10 + pub mod track;
+10
crates/library/src/entity/playlist.rs
··· 1 + #[derive(sqlx::FromRow, Default)] 2 + pub struct Playlist { 3 + pub id: String, 4 + pub name: String, 5 + pub image: Option<String>, 6 + pub description: Option<String>, 7 + pub folder_id: Option<String>, 8 + pub created_at: i64, 9 + pub updated_at: i64, 10 + }
+6
crates/library/src/entity/playlist_tracks.rs
··· 1 + #[derive(sqlx::FromRow, Default)] 2 + pub struct PlaylistTracks { 3 + pub id: String, 4 + pub playlist_id: String, 5 + pub track_id: String, 6 + }
+26
crates/library/src/entity/track.rs
··· 1 + #[derive(sqlx::FromRow, Default)] 2 + pub struct Track { 3 + pub id: String, 4 + pub path: String, 5 + pub title: String, 6 + pub artist: String, 7 + pub album: String, 8 + pub album_artist: String, 9 + pub bitrate: u32, 10 + pub composer: String, 11 + pub disc_number: u32, 12 + pub filesize: u32, 13 + pub frequency: u32, 14 + pub length: u32, 15 + pub track_number: Option<u32>, 16 + pub year: Option<u32>, 17 + pub year_string: Option<String>, 18 + pub genre: Option<String>, 19 + pub md5: String, 20 + pub album_art: Option<String>, 21 + pub artist_id: String, 22 + pub album_id: String, 23 + pub genre_id: String, 24 + pub created_at: i32, 25 + pub updated_at: i32, 26 + }
+20
crates/library/src/lib.rs
··· 1 + use std::env; 2 + 3 + use sqlx::{sqlite::SqliteConnectOptions, Error, Executor, Pool, Sqlite, SqlitePool}; 4 + 5 + pub mod audio_scan; 6 + pub mod entity; 7 + pub mod repo; 8 + 9 + pub async fn create_connection_pool() -> Result<Pool<Sqlite>, Error> { 10 + let db_url = env::var("DATABASE_URL").unwrap_or(":memory:".to_string()); 11 + let options = SqliteConnectOptions::new() 12 + .filename(db_url) 13 + .create_if_missing(true); 14 + let pool = SqlitePool::connect_with(options).await?; 15 + pool.execute(include_str!( 16 + "../migrations/20240923093823_create_tables.sql" 17 + )) 18 + .await?; 19 + Ok(pool) 20 + }
+70
crates/library/src/repo/album.rs
··· 1 + use crate::entity::album::Album; 2 + use sqlx::{Pool, Sqlite}; 3 + 4 + pub async fn save(pool: Pool<Sqlite>, album: Album) -> Result<(), sqlx::Error> { 5 + match sqlx::query( 6 + r#" 7 + INSERT INTO album ( 8 + id, 9 + title, 10 + artist, 11 + year, 12 + year_string, 13 + album_art, 14 + md5 15 + ) 16 + VALUES ($1, $2, $3, $4, $5, $6, $7) 17 + "#, 18 + ) 19 + .bind(&album.id) 20 + .bind(&album.title) 21 + .bind(&album.artist) 22 + .bind(album.year) 23 + .bind(&album.year_string) 24 + .bind(&album.album_art) 25 + .bind(&album.md5) 26 + .execute(&pool) 27 + .await 28 + { 29 + Ok(_) => {} 30 + Err(_e) => { 31 + // eprintln!("Error saving album: {:?}", e); 32 + } 33 + } 34 + Ok(()) 35 + } 36 + 37 + pub async fn find(pool: Pool<Sqlite>, id: &str) -> Result<Option<Album>, sqlx::Error> { 38 + match sqlx::query_as::<_, Album>( 39 + r#" 40 + SELECT * FROM album WHERE id = $1 41 + "#, 42 + ) 43 + .bind(id) 44 + .fetch_optional(&pool) 45 + .await 46 + { 47 + Ok(album) => Ok(album), 48 + Err(e) => { 49 + eprintln!("Error finding album: {:?}", e); 50 + Err(e) 51 + } 52 + } 53 + } 54 + 55 + pub async fn all(pool: Pool<Sqlite>) -> Result<Vec<Album>, sqlx::Error> { 56 + match sqlx::query_as::<_, Album>( 57 + r#" 58 + SELECT * FROM album 59 + "#, 60 + ) 61 + .fetch_all(&pool) 62 + .await 63 + { 64 + Ok(albums) => Ok(albums), 65 + Err(e) => { 66 + eprintln!("Error finding albums: {:?}", e); 67 + Err(e) 68 + } 69 + } 70 + }
+6
crates/library/src/repo/album_tracks.rs
··· 1 + use crate::entity::album_tracks::AlbumTracks; 2 + use sqlx::{Pool, Sqlite}; 3 + 4 + pub async fn save(pool: Pool<Sqlite>, album_track: AlbumTracks) {} 5 + 6 + pub async fn find(pool: Pool<Sqlite>) {}
+64
crates/library/src/repo/artist.rs
··· 1 + use crate::entity::artist::Artist; 2 + use sqlx::{Error, Pool, Sqlite}; 3 + 4 + pub async fn save(pool: Pool<Sqlite>, artist: Artist) -> Result<(), Error> { 5 + match sqlx::query( 6 + r#" 7 + INSERT INTO artist ( 8 + id, 9 + name, 10 + bio, 11 + image 12 + ) 13 + VALUES ($1, $2, $3, $4) 14 + "#, 15 + ) 16 + .bind(&artist.id) 17 + .bind(&artist.name) 18 + .bind(&artist.bio) 19 + .bind(&artist.image) 20 + .execute(&pool) 21 + .await 22 + { 23 + Ok(_) => {} 24 + Err(_e) => { 25 + // eprintln!("Error saving artist: {:?}", e); 26 + } 27 + } 28 + Ok(()) 29 + } 30 + 31 + pub async fn find(pool: Pool<Sqlite>, id: &str) -> Result<Option<Artist>, Error> { 32 + match sqlx::query_as::<_, Artist>( 33 + r#" 34 + SELECT * FROM artist WHERE id = $1 35 + "#, 36 + ) 37 + .bind(id) 38 + .fetch_optional(&pool) 39 + .await 40 + { 41 + Ok(artist) => Ok(artist), 42 + Err(e) => { 43 + eprintln!("Error finding artist: {:?}", e); 44 + Err(e) 45 + } 46 + } 47 + } 48 + 49 + pub async fn all(pool: Pool<Sqlite>) -> Result<Vec<Artist>, Error> { 50 + match sqlx::query_as::<_, Artist>( 51 + r#" 52 + SELECT * FROM artist 53 + "#, 54 + ) 55 + .fetch_all(&pool) 56 + .await 57 + { 58 + Ok(artists) => Ok(artists), 59 + Err(e) => { 60 + eprintln!("Error finding artists: {:?}", e); 61 + Err(e) 62 + } 63 + } 64 + }
+6
crates/library/src/repo/artist_tracks.rs
··· 1 + use sqlx::{Pool, Sqlite}; 2 + use crate::entity::artist_tracks::ArtistTracks; 3 + 4 + pub async fn save(pool: Pool<Sqlite>, artist_tracks: ArtistTracks) {} 5 + 6 + pub async fn all(pool: Pool<Sqlite>) {}
+6
crates/library/src/repo/favourites.rs
··· 1 + use crate::entity::favourites::Favourites; 2 + use sqlx::{Pool, Sqlite}; 3 + 4 + pub async fn save(pool: Pool<Sqlite>, favourite: Favourites) {} 5 + 6 + pub async fn all(pool: Pool<Sqlite>) {}
+8
crates/library/src/repo/folder.rs
··· 1 + use crate::entity::folder::Folder; 2 + use sqlx::{Pool, Sqlite}; 3 + 4 + pub async fn save(pool: Pool<Sqlite>, folder: Folder) {} 5 + 6 + pub async fn find(pool: Pool<Sqlite>) {} 7 + 8 + pub async fn all(pool: Pool<Sqlite>) {}
crates/library/src/repo/genre.rs

This is a binary file and will not be displayed.

+10
crates/library/src/repo/mod.rs
··· 1 + pub mod album; 2 + pub mod album_tracks; 3 + pub mod artist; 4 + pub mod artist_tracks; 5 + pub mod favourites; 6 + pub mod folder; 7 + pub mod genre; 8 + pub mod playlist; 9 + pub mod playlist_tracks; 10 + pub mod track;
+8
crates/library/src/repo/playlist.rs
··· 1 + use crate::entity::playlist::Playlist; 2 + use sqlx::{Pool, Sqlite}; 3 + 4 + pub async fn save(pool: Pool<Sqlite>, playlist: Playlist) {} 5 + 6 + pub async fn find(pool: Pool<Sqlite>) {} 7 + 8 + pub async fn all(pool: Pool<Sqlite>) {}
+6
crates/library/src/repo/playlist_tracks.rs
··· 1 + use crate::entity::playlist_tracks::PlaylistTracks; 2 + use sqlx::{Pool, Sqlite}; 3 + 4 + pub async fn save(pool: Pool<Sqlite>, playlist_track: PlaylistTracks) {} 5 + 6 + pub async fn find(pool: Pool<Sqlite>) {}
+85
crates/library/src/repo/track.rs
··· 1 + use crate::entity::track::Track; 2 + use sqlx::{Error, Pool, Sqlite}; 3 + 4 + pub async fn save(pool: Pool<Sqlite>, track: Track) -> Result<(), Error> { 5 + match sqlx::query( 6 + r#" 7 + INSERT INTO track ( 8 + id, 9 + path, 10 + title, 11 + artist, 12 + album, 13 + genre, 14 + year, 15 + track_number, 16 + disc_number, 17 + year_string, 18 + composer, 19 + album_artist, 20 + bitrate, 21 + frequency, 22 + filesize, 23 + length, 24 + md5, 25 + created_at, 26 + updated_at, 27 + artist_id, 28 + album_id 29 + ) 30 + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21) 31 + "#, 32 + ) 33 + .bind(&track.id) 34 + .bind(&track.path) 35 + .bind(&track.title) 36 + .bind(&track.artist) 37 + .bind(&track.album) 38 + .bind(track.genre) 39 + .bind(track.year) 40 + .bind(track.track_number) 41 + .bind(track.disc_number) 42 + .bind(&track.year_string) 43 + .bind(&track.composer) 44 + .bind(&track.album_artist) 45 + .bind(track.bitrate) 46 + .bind(track.frequency) 47 + .bind(track.filesize) 48 + .bind(track.length) 49 + .bind(&track.md5) 50 + .bind(track.created_at) 51 + .bind(track.updated_at) 52 + .bind(&track.artist_id) 53 + .bind(&track.album_id) 54 + .execute(&pool) 55 + .await { 56 + Ok(_) => {} 57 + Err(_e) => { 58 + // eprintln!("Error saving track: {:?}", e); 59 + } 60 + } 61 + Ok(()) 62 + } 63 + 64 + pub async fn find(pool: Pool<Sqlite>, id: &str) -> Result<Option<Track>, Error> { 65 + let result: Option<Track> = sqlx::query_as("SELECT * FROM track WHERE id = $1") 66 + .bind(id) 67 + .fetch_optional(&pool) 68 + .await?; 69 + Ok(result) 70 + } 71 + 72 + pub async fn find_by_md5(pool: Pool<Sqlite>, md5: &str) -> Result<Option<Track>, Error> { 73 + let result: Option<Track> = sqlx::query_as("SELECT * FROM track WHERE md5 = $1") 74 + .bind(md5) 75 + .fetch_optional(&pool) 76 + .await?; 77 + Ok(result) 78 + } 79 + 80 + pub async fn all(pool: Pool<Sqlite>) -> Result<Vec<Track>, Error> { 81 + let result: Vec<Track> = sqlx::query_as("SELECT * FROM track") 82 + .fetch_all(&pool) 83 + .await?; 84 + Ok(result) 85 + }