diff options
| author | salmonik <raisersoft@proton.me> | 2026-05-09 15:14:33 +0200 |
|---|---|---|
| committer | salmonik <raisersoft@proton.me> | 2026-05-09 15:14:33 +0200 |
| commit | b3b7f0f65295f2100eb3c9880e870349c43701a6 (patch) | |
| tree | 1b24e6eecc8d7fbe3720208fb496604fe430ab45 | |
| parent | Add TODO for major rewrite phases (diff) | |
| download | rsplayer-b3b7f0f65295f2100eb3c9880e870349c43701a6.tar.gz rsplayer-b3b7f0f65295f2100eb3c9880e870349c43701a6.zip | |
Major rewrite: play command, queue display, and shuffle modes
- Play command: no args queues to end (play only if queue empty + player playing),
-i inserts after current and skips, -n inserts after current, removed -l flag
- Queue display: detect terminal size, use pager only if queue exceeds terminal rows
- Shuffle modes: always remember original queue, restore on 'shuffle none',
album shuffle shuffles within each album's range separately
Diffstat (limited to '')
| -rw-r--r-- | Cargo.lock | 110 | ||||
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | src/cli.rs | 11 | ||||
| -rw-r--r-- | src/daemon.rs | 14 | ||||
| -rw-r--r-- | src/queue.rs | 85 |
5 files changed, 200 insertions, 21 deletions
| @@ -146,7 +146,7 @@ dependencies = [ | |||
| 146 | "futures-lite", | 146 | "futures-lite", |
| 147 | "parking", | 147 | "parking", |
| 148 | "polling", | 148 | "polling", |
| 149 | "rustix", | 149 | "rustix 1.1.4", |
| 150 | "slab", | 150 | "slab", |
| 151 | "windows-sys 0.61.2", | 151 | "windows-sys 0.61.2", |
| 152 | ] | 152 | ] |
| @@ -177,7 +177,7 @@ dependencies = [ | |||
| 177 | "cfg-if", | 177 | "cfg-if", |
| 178 | "event-listener", | 178 | "event-listener", |
| 179 | "futures-lite", | 179 | "futures-lite", |
| 180 | "rustix", | 180 | "rustix 1.1.4", |
| 181 | ] | 181 | ] |
| 182 | 182 | ||
| 183 | [[package]] | 183 | [[package]] |
| @@ -203,7 +203,7 @@ dependencies = [ | |||
| 203 | "cfg-if", | 203 | "cfg-if", |
| 204 | "futures-core", | 204 | "futures-core", |
| 205 | "futures-io", | 205 | "futures-io", |
| 206 | "rustix", | 206 | "rustix 1.1.4", |
| 207 | "signal-hook-registry", | 207 | "signal-hook-registry", |
| 208 | "slab", | 208 | "slab", |
| 209 | "windows-sys 0.61.2", | 209 | "windows-sys 0.61.2", |
| @@ -1329,6 +1329,12 @@ dependencies = [ | |||
| 1329 | 1329 | ||
| 1330 | [[package]] | 1330 | [[package]] |
| 1331 | name = "linux-raw-sys" | 1331 | name = "linux-raw-sys" |
| 1332 | version = "0.4.15" | ||
| 1333 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1334 | checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" | ||
| 1335 | |||
| 1336 | [[package]] | ||
| 1337 | name = "linux-raw-sys" | ||
| 1332 | version = "0.12.1" | 1338 | version = "0.12.1" |
| 1333 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1339 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 1334 | checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" | 1340 | checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" |
| @@ -1707,7 +1713,7 @@ dependencies = [ | |||
| 1707 | "concurrent-queue", | 1713 | "concurrent-queue", |
| 1708 | "hermit-abi", | 1714 | "hermit-abi", |
| 1709 | "pin-project-lite", | 1715 | "pin-project-lite", |
| 1710 | "rustix", | 1716 | "rustix 1.1.4", |
| 1711 | "windows-sys 0.61.2", | 1717 | "windows-sys 0.61.2", |
| 1712 | ] | 1718 | ] |
| 1713 | 1719 | ||
| @@ -1989,6 +1995,7 @@ dependencies = [ | |||
| 1989 | "serde_json", | 1995 | "serde_json", |
| 1990 | "symphonia", | 1996 | "symphonia", |
| 1991 | "tempfile", | 1997 | "tempfile", |
| 1998 | "terminal_size", | ||
| 1992 | "tokio", | 1999 | "tokio", |
| 1993 | "toml", | 2000 | "toml", |
| 1994 | ] | 2001 | ] |
| @@ -2035,6 +2042,19 @@ dependencies = [ | |||
| 2035 | 2042 | ||
| 2036 | [[package]] | 2043 | [[package]] |
| 2037 | name = "rustix" | 2044 | name = "rustix" |
| 2045 | version = "0.38.44" | ||
| 2046 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2047 | checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" | ||
| 2048 | dependencies = [ | ||
| 2049 | "bitflags 2.11.1", | ||
| 2050 | "errno", | ||
| 2051 | "libc", | ||
| 2052 | "linux-raw-sys 0.4.15", | ||
| 2053 | "windows-sys 0.52.0", | ||
| 2054 | ] | ||
| 2055 | |||
| 2056 | [[package]] | ||
| 2057 | name = "rustix" | ||
| 2038 | version = "1.1.4" | 2058 | version = "1.1.4" |
| 2039 | source = "registry+https://github.com/rust-lang/crates.io-index" | 2059 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 2040 | checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" | 2060 | checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" |
| @@ -2042,7 +2062,7 @@ dependencies = [ | |||
| 2042 | "bitflags 2.11.1", | 2062 | "bitflags 2.11.1", |
| 2043 | "errno", | 2063 | "errno", |
| 2044 | "libc", | 2064 | "libc", |
| 2045 | "linux-raw-sys", | 2065 | "linux-raw-sys 0.12.1", |
| 2046 | "windows-sys 0.61.2", | 2066 | "windows-sys 0.61.2", |
| 2047 | ] | 2067 | ] |
| 2048 | 2068 | ||
| @@ -2595,11 +2615,21 @@ dependencies = [ | |||
| 2595 | "fastrand", | 2615 | "fastrand", |
| 2596 | "getrandom 0.4.2", | 2616 | "getrandom 0.4.2", |
| 2597 | "once_cell", | 2617 | "once_cell", |
| 2598 | "rustix", | 2618 | "rustix 1.1.4", |
| 2599 | "windows-sys 0.61.2", | 2619 | "windows-sys 0.61.2", |
| 2600 | ] | 2620 | ] |
| 2601 | 2621 | ||
| 2602 | [[package]] | 2622 | [[package]] |
| 2623 | name = "terminal_size" | ||
| 2624 | version = "0.3.0" | ||
| 2625 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2626 | checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" | ||
| 2627 | dependencies = [ | ||
| 2628 | "rustix 0.38.44", | ||
| 2629 | "windows-sys 0.48.0", | ||
| 2630 | ] | ||
| 2631 | |||
| 2632 | [[package]] | ||
| 2603 | name = "thiserror" | 2633 | name = "thiserror" |
| 2604 | version = "1.0.69" | 2634 | version = "1.0.69" |
| 2605 | source = "registry+https://github.com/rust-lang/crates.io-index" | 2635 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| @@ -3310,6 +3340,15 @@ dependencies = [ | |||
| 3310 | 3340 | ||
| 3311 | [[package]] | 3341 | [[package]] |
| 3312 | name = "windows-sys" | 3342 | name = "windows-sys" |
| 3343 | version = "0.48.0" | ||
| 3344 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 3345 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" | ||
| 3346 | dependencies = [ | ||
| 3347 | "windows-targets 0.48.5", | ||
| 3348 | ] | ||
| 3349 | |||
| 3350 | [[package]] | ||
| 3351 | name = "windows-sys" | ||
| 3313 | version = "0.52.0" | 3352 | version = "0.52.0" |
| 3314 | source = "registry+https://github.com/rust-lang/crates.io-index" | 3353 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 3315 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" | 3354 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" |
| @@ -3352,6 +3391,21 @@ dependencies = [ | |||
| 3352 | 3391 | ||
| 3353 | [[package]] | 3392 | [[package]] |
| 3354 | name = "windows-targets" | 3393 | name = "windows-targets" |
| 3394 | version = "0.48.5" | ||
| 3395 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 3396 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" | ||
| 3397 | dependencies = [ | ||
| 3398 | "windows_aarch64_gnullvm 0.48.5", | ||
| 3399 | "windows_aarch64_msvc 0.48.5", | ||
| 3400 | "windows_i686_gnu 0.48.5", | ||
| 3401 | "windows_i686_msvc 0.48.5", | ||
| 3402 | "windows_x86_64_gnu 0.48.5", | ||
| 3403 | "windows_x86_64_gnullvm 0.48.5", | ||
| 3404 | "windows_x86_64_msvc 0.48.5", | ||
| 3405 | ] | ||
| 3406 | |||
| 3407 | [[package]] | ||
| 3408 | name = "windows-targets" | ||
| 3355 | version = "0.52.6" | 3409 | version = "0.52.6" |
| 3356 | source = "registry+https://github.com/rust-lang/crates.io-index" | 3410 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 3357 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" | 3411 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" |
| @@ -3418,6 +3472,12 @@ checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" | |||
| 3418 | 3472 | ||
| 3419 | [[package]] | 3473 | [[package]] |
| 3420 | name = "windows_aarch64_gnullvm" | 3474 | name = "windows_aarch64_gnullvm" |
| 3475 | version = "0.48.5" | ||
| 3476 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 3477 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" | ||
| 3478 | |||
| 3479 | [[package]] | ||
| 3480 | name = "windows_aarch64_gnullvm" | ||
| 3421 | version = "0.52.6" | 3481 | version = "0.52.6" |
| 3422 | source = "registry+https://github.com/rust-lang/crates.io-index" | 3482 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 3423 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" | 3483 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" |
| @@ -3436,6 +3496,12 @@ checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" | |||
| 3436 | 3496 | ||
| 3437 | [[package]] | 3497 | [[package]] |
| 3438 | name = "windows_aarch64_msvc" | 3498 | name = "windows_aarch64_msvc" |
| 3499 | version = "0.48.5" | ||
| 3500 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 3501 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" | ||
| 3502 | |||
| 3503 | [[package]] | ||
| 3504 | name = "windows_aarch64_msvc" | ||
| 3439 | version = "0.52.6" | 3505 | version = "0.52.6" |
| 3440 | source = "registry+https://github.com/rust-lang/crates.io-index" | 3506 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 3441 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" | 3507 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" |
| @@ -3454,6 +3520,12 @@ checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" | |||
| 3454 | 3520 | ||
| 3455 | [[package]] | 3521 | [[package]] |
| 3456 | name = "windows_i686_gnu" | 3522 | name = "windows_i686_gnu" |
| 3523 | version = "0.48.5" | ||
| 3524 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 3525 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" | ||
| 3526 | |||
| 3527 | [[package]] | ||
| 3528 | name = "windows_i686_gnu" | ||
| 3457 | version = "0.52.6" | 3529 | version = "0.52.6" |
| 3458 | source = "registry+https://github.com/rust-lang/crates.io-index" | 3530 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 3459 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" | 3531 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" |
| @@ -3484,6 +3556,12 @@ checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" | |||
| 3484 | 3556 | ||
| 3485 | [[package]] | 3557 | [[package]] |
| 3486 | name = "windows_i686_msvc" | 3558 | name = "windows_i686_msvc" |
| 3559 | version = "0.48.5" | ||
| 3560 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 3561 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" | ||
| 3562 | |||
| 3563 | [[package]] | ||
| 3564 | name = "windows_i686_msvc" | ||
| 3487 | version = "0.52.6" | 3565 | version = "0.52.6" |
| 3488 | source = "registry+https://github.com/rust-lang/crates.io-index" | 3566 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 3489 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" | 3567 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" |
| @@ -3502,6 +3580,12 @@ checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" | |||
| 3502 | 3580 | ||
| 3503 | [[package]] | 3581 | [[package]] |
| 3504 | name = "windows_x86_64_gnu" | 3582 | name = "windows_x86_64_gnu" |
| 3583 | version = "0.48.5" | ||
| 3584 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 3585 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" | ||
| 3586 | |||
| 3587 | [[package]] | ||
| 3588 | name = "windows_x86_64_gnu" | ||
| 3505 | version = "0.52.6" | 3589 | version = "0.52.6" |
| 3506 | source = "registry+https://github.com/rust-lang/crates.io-index" | 3590 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 3507 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" | 3591 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" |
| @@ -3520,6 +3604,12 @@ checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" | |||
| 3520 | 3604 | ||
| 3521 | [[package]] | 3605 | [[package]] |
| 3522 | name = "windows_x86_64_gnullvm" | 3606 | name = "windows_x86_64_gnullvm" |
| 3607 | version = "0.48.5" | ||
| 3608 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 3609 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" | ||
| 3610 | |||
| 3611 | [[package]] | ||
| 3612 | name = "windows_x86_64_gnullvm" | ||
| 3523 | version = "0.52.6" | 3613 | version = "0.52.6" |
| 3524 | source = "registry+https://github.com/rust-lang/crates.io-index" | 3614 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 3525 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" | 3615 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" |
| @@ -3538,6 +3628,12 @@ checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" | |||
| 3538 | 3628 | ||
| 3539 | [[package]] | 3629 | [[package]] |
| 3540 | name = "windows_x86_64_msvc" | 3630 | name = "windows_x86_64_msvc" |
| 3631 | version = "0.48.5" | ||
| 3632 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 3633 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" | ||
| 3634 | |||
| 3635 | [[package]] | ||
| 3636 | name = "windows_x86_64_msvc" | ||
| 3541 | version = "0.52.6" | 3637 | version = "0.52.6" |
| 3542 | source = "registry+https://github.com/rust-lang/crates.io-index" | 3638 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 3543 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" | 3639 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" |
| @@ -3702,7 +3798,7 @@ dependencies = [ | |||
| 3702 | "hex", | 3798 | "hex", |
| 3703 | "libc", | 3799 | "libc", |
| 3704 | "ordered-stream", | 3800 | "ordered-stream", |
| 3705 | "rustix", | 3801 | "rustix 1.1.4", |
| 3706 | "serde", | 3802 | "serde", |
| 3707 | "serde_repr", | 3803 | "serde_repr", |
| 3708 | "tracing", | 3804 | "tracing", |
| @@ -33,6 +33,7 @@ libc = "0.2.186" | |||
| 33 | ctrlc = "3.5.2" | 33 | ctrlc = "3.5.2" |
| 34 | rand = "0.10.1" | 34 | rand = "0.10.1" |
| 35 | notify-rust = "4.17.0" | 35 | notify-rust = "4.17.0" |
| 36 | terminal_size = "0.3" | ||
| 36 | 37 | ||
| 37 | [dev-dependencies] | 38 | [dev-dependencies] |
| 38 | tempfile = "3.17" | 39 | tempfile = "3.17" |
| @@ -21,15 +21,12 @@ pub enum Commands { | |||
| 21 | Restart, | 21 | Restart, |
| 22 | /// Play a track, album, or artist | 22 | /// Play a track, album, or artist |
| 23 | Play { | 23 | Play { |
| 24 | /// Play immediately (add after current and skip to it) | 24 | /// Add after current track and skip to it |
| 25 | #[arg(short = 'i', long = "now", group = "position")] | 25 | #[arg(short = 'i', long = "now")] |
| 26 | now: bool, | 26 | now: bool, |
| 27 | /// Add to queue after current track (don't skip) | 27 | /// Add to queue after current track (don't skip) |
| 28 | #[arg(short = 'n', long = "next", group = "position")] | 28 | #[arg(short = 'n', long = "next")] |
| 29 | next: bool, | 29 | next: bool, |
| 30 | /// Add to end of queue (default) | ||
| 31 | #[arg(short = 'l', long = "last", group = "position")] | ||
| 32 | last: bool, | ||
| 33 | #[arg(value_name = "QUERY")] | 30 | #[arg(value_name = "QUERY")] |
| 34 | query: Option<String>, | 31 | query: Option<String>, |
| 35 | }, | 32 | }, |
| @@ -126,7 +123,7 @@ impl Cli { | |||
| 126 | }; | 123 | }; |
| 127 | crate::daemon::send_command(format!("play {} {}", pos, q))?; | 124 | crate::daemon::send_command(format!("play {} {}", pos, q))?; |
| 128 | } else { | 125 | } else { |
| 129 | crate::daemon::send_command("play".to_string())?; | 126 | crate::daemon::send_command("play last".to_string())?; |
| 130 | } | 127 | } |
| 131 | } | 128 | } |
| 132 | Commands::Pause => { | 129 | Commands::Pause => { |
diff --git a/src/daemon.rs b/src/daemon.rs index e88669a..f4a72b7 100644 --- a/src/daemon.rs +++ b/src/daemon.rs | |||
| @@ -399,9 +399,9 @@ fn process_command( | |||
| 399 | format!("Queued next: {}\n", path_str) | 399 | format!("Queued next: {}\n", path_str) |
| 400 | } | 400 | } |
| 401 | _ => { | 401 | _ => { |
| 402 | let was_playing = audio.is_playing(); | 402 | let was_empty = q.is_empty(); |
| 403 | q.add_track(path.clone()); | 403 | q.add_track(path.clone()); |
| 404 | if !was_playing { | 404 | if was_empty && audio.is_playing() { |
| 405 | let track = Track::from_path(path.clone()); | 405 | let track = Track::from_path(path.clone()); |
| 406 | audio.play(path); | 406 | audio.play(path); |
| 407 | notification::notify_track(&track); | 407 | notification::notify_track(&track); |
| @@ -452,7 +452,8 @@ fn process_command( | |||
| 452 | for file in &files { | 452 | for file in &files { |
| 453 | q.add_track(file.clone()); | 453 | q.add_track(file.clone()); |
| 454 | } | 454 | } |
| 455 | if !audio.is_playing() | 455 | if was_empty |
| 456 | && audio.is_playing() | ||
| 456 | && let Some(track) = q.current() | 457 | && let Some(track) = q.current() |
| 457 | { | 458 | { |
| 458 | audio.play(track.path.clone()); | 459 | audio.play(track.path.clone()); |
| @@ -519,8 +520,11 @@ fn process_command( | |||
| 519 | } | 520 | } |
| 520 | } | 521 | } |
| 521 | } | 522 | } |
| 522 | // Use pager if output is long (more than 24 lines) | 523 | // Use pager if queue is longer than terminal height |
| 523 | if output.lines().count() > 24 { | 524 | let terminal_rows = terminal_size::terminal_size() |
| 525 | .map(|(w, _)| w.0 as usize) | ||
| 526 | .unwrap_or(24); | ||
| 527 | if output.lines().count() > terminal_rows { | ||
| 524 | use std::process::{Command, Stdio}; | 528 | use std::process::{Command, Stdio}; |
| 525 | let pager = Command::new("less").arg("-R").stdin(Stdio::piped()).spawn(); | 529 | let pager = Command::new("less").arg("-R").stdin(Stdio::piped()).spawn(); |
| 526 | if let Ok(mut child) = pager { | 530 | if let Ok(mut child) = pager { |
diff --git a/src/queue.rs b/src/queue.rs index 9e8e1af..109b748 100644 --- a/src/queue.rs +++ b/src/queue.rs | |||
| @@ -124,6 +124,7 @@ pub struct Queue { | |||
| 124 | position: usize, | 124 | position: usize, |
| 125 | shuffle: ShuffleMode, | 125 | shuffle: ShuffleMode, |
| 126 | shuffled_indices: Vec<usize>, | 126 | shuffled_indices: Vec<usize>, |
| 127 | original_tracks: Vec<Track>, | ||
| 127 | } | 128 | } |
| 128 | 129 | ||
| 129 | impl Default for Queue { | 130 | impl Default for Queue { |
| @@ -139,6 +140,7 @@ impl Queue { | |||
| 139 | position: 0, | 140 | position: 0, |
| 140 | shuffle: ShuffleMode::None, | 141 | shuffle: ShuffleMode::None, |
| 141 | shuffled_indices: Vec::new(), | 142 | shuffled_indices: Vec::new(), |
| 143 | original_tracks: Vec::new(), | ||
| 142 | } | 144 | } |
| 143 | } | 145 | } |
| 144 | 146 | ||
| @@ -162,8 +164,38 @@ impl Queue { | |||
| 162 | } | 164 | } |
| 163 | 165 | ||
| 164 | pub fn set_shuffle(&mut self, mode: ShuffleMode) { | 166 | pub fn set_shuffle(&mut self, mode: ShuffleMode) { |
| 165 | self.shuffle = mode; | 167 | match mode { |
| 166 | self.update_shuffle_indices(); | 168 | ShuffleMode::None => { |
| 169 | self.shuffle = ShuffleMode::None; | ||
| 170 | self.restore_from_original(); | ||
| 171 | } | ||
| 172 | ShuffleMode::All => { | ||
| 173 | self.original_tracks = self.tracks.clone(); | ||
| 174 | self.shuffle = ShuffleMode::All; | ||
| 175 | self.update_shuffle_indices(); | ||
| 176 | } | ||
| 177 | ShuffleMode::Album => { | ||
| 178 | self.original_tracks = self.tracks.clone(); | ||
| 179 | self.shuffle = ShuffleMode::Album; | ||
| 180 | self.update_shuffle_indices_album(); | ||
| 181 | } | ||
| 182 | } | ||
| 183 | } | ||
| 184 | |||
| 185 | fn restore_from_original(&mut self) { | ||
| 186 | if self.original_tracks.is_empty() { | ||
| 187 | self.shuffled_indices.clear(); | ||
| 188 | return; | ||
| 189 | } | ||
| 190 | |||
| 191 | let current_pos = self.position; | ||
| 192 | let played: Vec<Track> = self.tracks[..current_pos].to_vec(); | ||
| 193 | let unplayed_original: Vec<Track> = self.original_tracks[current_pos..].to_vec(); | ||
| 194 | |||
| 195 | self.tracks = played; | ||
| 196 | self.tracks.extend(unplayed_original); | ||
| 197 | self.position = current_pos; | ||
| 198 | self.shuffled_indices.clear(); | ||
| 167 | } | 199 | } |
| 168 | 200 | ||
| 169 | fn update_shuffle_indices(&mut self) { | 201 | fn update_shuffle_indices(&mut self) { |
| @@ -180,6 +212,55 @@ impl Queue { | |||
| 180 | } | 212 | } |
| 181 | } | 213 | } |
| 182 | 214 | ||
| 215 | fn update_shuffle_indices_album(&mut self) { | ||
| 216 | let len = self.tracks.len(); | ||
| 217 | self.shuffled_indices = (0..len).collect(); | ||
| 218 | |||
| 219 | let mut rng = rand::rng(); | ||
| 220 | let pos = self.position.min(len.saturating_sub(1)); | ||
| 221 | |||
| 222 | if pos == 0 && len > 1 { | ||
| 223 | self.shuffle_album_range(0..len, &mut rng); | ||
| 224 | } else if pos + 1 < len { | ||
| 225 | self.shuffle_album_range(pos + 1..len, &mut rng); | ||
| 226 | } | ||
| 227 | } | ||
| 228 | |||
| 229 | fn shuffle_album_range(&mut self, range: std::ops::Range<usize>, rng: &mut impl rand::Rng) { | ||
| 230 | if range.start >= range.end { | ||
| 231 | return; | ||
| 232 | } | ||
| 233 | |||
| 234 | let mut album_ranges: Vec<(usize, usize)> = Vec::new(); | ||
| 235 | let mut current_album: Option<&str> = None; | ||
| 236 | let mut range_start: Option<usize> = None; | ||
| 237 | |||
| 238 | for i in range.clone() { | ||
| 239 | let album = self.tracks.get(i).and_then(|t| t.album.as_deref()); | ||
| 240 | match (current_album, range_start) { | ||
| 241 | (None, None) => { | ||
| 242 | current_album = album; | ||
| 243 | range_start = Some(i); | ||
| 244 | } | ||
| 245 | (Some(_), Some(start)) if album != current_album => { | ||
| 246 | album_ranges.push((start, i)); | ||
| 247 | current_album = album; | ||
| 248 | range_start = Some(i); | ||
| 249 | } | ||
| 250 | _ => {} | ||
| 251 | } | ||
| 252 | } | ||
| 253 | if let Some(start) = range_start { | ||
| 254 | album_ranges.push((start, range.end)); | ||
| 255 | } | ||
| 256 | |||
| 257 | for (start, end) in album_ranges { | ||
| 258 | if start + 1 < end { | ||
| 259 | self.shuffled_indices[start..end].shuffle(rng); | ||
| 260 | } | ||
| 261 | } | ||
| 262 | } | ||
| 263 | |||
| 183 | pub fn current(&self) -> Option<&Track> { | 264 | pub fn current(&self) -> Option<&Track> { |
| 184 | if self.tracks.is_empty() { | 265 | if self.tracks.is_empty() { |
| 185 | None | 266 | None |
