mirror of
https://github.com/socatlolmeow/drift.git
synced 2026-11-04 03:37:18 +00:00
feat: discord presence, cached audio playback, multiinstance safety
Add
- Discord rich presence ("Listening to", cover, progress, Listen Along
button). enable via [discord] client_id in config.toml : retries quietly
if Discord isn't running. new dep: discord-rich-presence.
- :save! / :w! to overwrite a playlist. Plain :save now refuses to
clobber an existing name.
Change
- Download audio with yt-dlp into the cache dir and play the local file
(mpv --ytdl=no) instead of streaming. Keep the last 40 files and
prefetch the next queued track.
- show the the actual yt-dlp/mpv error on playback failure instead of the
generic "update yt-dlp" hint; allow wider status messages (70 - 120 char).
- Split artists from YouTube's linked artist runs and yt-dlp's 'artists'
list (new Track::artists) rather than guessing from the display string.
Fallback splitter keeps names like "Tyler, The Creator" whole and
matches separators case-insensitively. (shit)
- Restyle selection (accent bold text + bar) and tab bar (underlined
active tab instead of pills)
- Share one ureq agent across yt Music requests
Fix
- Multiple drift instances: only the first (flock on session.lock) owns
the session, and playlist saves merge with what other instances wrote.
- Collection picker no longer steals keys while typing.
- "Play next" now shifts `played` indices so shuffle history stays right.
- Leaving the queue for a playlist/result list marks the queue as done.
- Replace unwrap() in lyrics sorting with total_cmp (NaN-safe).
This commit is contained in:
parent
a7f101d1e7
commit
eb6b16e70b
16 changed files with 966 additions and 171 deletions
|
|
@ -22,6 +22,37 @@ impl Session {
|
|||
Ok(dir.join("drift").join("session.json"))
|
||||
}
|
||||
|
||||
/* The first drift to start owns the saved session. Later ones neither
|
||||
restore nor overwrite it. The lock goes away when the process exits. */
|
||||
#[cfg(unix)]
|
||||
pub fn claim() -> bool {
|
||||
use std::os::unix::io::AsRawFd;
|
||||
let Ok(path) = Self::path().map(|p| p.with_file_name("session.lock")) else {
|
||||
return true;
|
||||
};
|
||||
if let Some(dir) = path.parent() {
|
||||
let _ = fs::create_dir_all(dir);
|
||||
}
|
||||
let Ok(file) = fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.truncate(false)
|
||||
.write(true)
|
||||
.open(&path)
|
||||
else {
|
||||
return true;
|
||||
};
|
||||
let ok = unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_EX | libc::LOCK_NB) } == 0;
|
||||
if ok {
|
||||
std::mem::forget(file);
|
||||
}
|
||||
ok
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
pub fn claim() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub fn exists() -> bool {
|
||||
Self::path().is_ok_and(|p| p.exists())
|
||||
}
|
||||
|
|
@ -75,6 +106,7 @@ mod tests {
|
|||
id: id.into(),
|
||||
title: "T".into(),
|
||||
artist: "A".into(),
|
||||
artists: Vec::new(),
|
||||
album: None,
|
||||
duration: Some(200),
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue