cbd-tui: show the album year, not the full release date
A notification has one line for the album, and "album (1977-10-28)" spends it on a day nobody asked about. `release_date` is whatever the provider's API (or fsdy's sidecar TOML) said and is not always ISO 8601, so `release_year` reads the leading four digits of a year-first date and returns None for anything else — an unparseable date is dropped rather than shown raw or half-parsed, which also keeps the "no date, no parentheses" path doing the work. `get(..4)` is the safe form: a short string or a multi-byte boundary yields None instead of panicking, and the tests pin both down. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
bbebee0b4f
commit
1228c7cb70
|
|
@ -630,19 +630,19 @@ fn notify_now_playing(track: &Track) {
|
|||
}
|
||||
}
|
||||
|
||||
/// The notification body: the track, and on its own line the album with the
|
||||
/// release date the provider gave. Most providers leave `release_date` unset
|
||||
/// (it is an optional proto field, so absent reads as ""), which is why the
|
||||
/// parentheses belong to the date and not to the album line — otherwise a
|
||||
/// dateless album shows up as "Album ()".
|
||||
/// The notification body: the track, and on its own line the album with its
|
||||
/// release year. Most providers leave `release_date` unset (it is an optional
|
||||
/// proto field, so absent reads as ""), which is why the parentheses belong to
|
||||
/// the year and not to the album line — otherwise a dateless album shows up as
|
||||
/// "Album ()".
|
||||
#[cfg(feature = "notifications")]
|
||||
fn notification_body(track: &Track) -> String {
|
||||
let Some(album) = &track.album else {
|
||||
return format!("{} by {}", track.title, track.artist);
|
||||
};
|
||||
let released = match album.release_date() {
|
||||
"" => String::new(),
|
||||
date => format!(" ({date})"),
|
||||
let released = match release_year(album.release_date()) {
|
||||
Some(year) => format!(" ({year})"),
|
||||
None => String::new(),
|
||||
};
|
||||
format!(
|
||||
"{} by {}\n\n{}{released}",
|
||||
|
|
@ -650,6 +650,21 @@ fn notification_body(track: &Track) -> String {
|
|||
)
|
||||
}
|
||||
|
||||
/// The year in a provider's `release_date`, for a notification that has one
|
||||
/// line to spend on the album.
|
||||
///
|
||||
/// The strings are not all ISO 8601 — each provider passes through whatever
|
||||
/// its API or (for `fsdy`) the sidecar TOML said — so this reads the leading
|
||||
/// four digits of a `YYYY`/`YYYY-MM-DD`/`YYYY/MM/DD` date and gives up on
|
||||
/// anything else rather than guessing. An unparseable date is dropped, not
|
||||
/// shown raw: it is metadata noise, and a notification is not the place to
|
||||
/// debug it.
|
||||
#[cfg(feature = "notifications")]
|
||||
fn release_year(release_date: &str) -> Option<&str> {
|
||||
let year = release_date.trim().get(..4)?;
|
||||
year.chars().all(|c| c.is_ascii_digit()).then_some(year)
|
||||
}
|
||||
|
||||
/// Built without the `notifications` feature: nothing to show
|
||||
/// (architecture/build-features.md D1).
|
||||
#[cfg(not(feature = "notifications"))]
|
||||
|
|
@ -700,13 +715,15 @@ mod tests {
|
|||
notification_body(&track)
|
||||
}
|
||||
|
||||
/// A full date is reduced to its year; a bare year is already one.
|
||||
#[cfg(feature = "notifications")]
|
||||
#[test]
|
||||
fn notification_shows_the_release_date_when_there_is_one() {
|
||||
fn notification_shows_the_release_year_when_there_is_one() {
|
||||
assert_eq!(
|
||||
body_for(Some("1977-10-28")),
|
||||
"title by artist\n\nalbum (1977-10-28)"
|
||||
"title by artist\n\nalbum (1977)"
|
||||
);
|
||||
assert_eq!(body_for(Some("1977")), "title by artist\n\nalbum (1977)");
|
||||
}
|
||||
|
||||
/// No date must mean no parentheses, whether the provider left the field
|
||||
|
|
@ -718,6 +735,31 @@ mod tests {
|
|||
assert_eq!(body_for(Some("")), "title by artist\n\nalbum");
|
||||
}
|
||||
|
||||
/// Providers hand through whatever their API said, so a date that is not
|
||||
/// year-first is dropped rather than shown raw or half-parsed. Nothing
|
||||
/// here may panic — `get(..4)` has to survive a short string and a
|
||||
/// multi-byte boundary.
|
||||
#[cfg(feature = "notifications")]
|
||||
#[test]
|
||||
fn an_unparseable_release_date_is_left_out() {
|
||||
for date in ["Oct 1977", "77", "-", "жизнь", "12/05/1977", "197"] {
|
||||
assert_eq!(
|
||||
body_for(Some(date)),
|
||||
"title by artist\n\nalbum",
|
||||
"date {date:?} should not reach the notification"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// The year is taken from the front, whatever separator follows it.
|
||||
#[cfg(feature = "notifications")]
|
||||
#[test]
|
||||
fn the_year_is_read_from_the_front_of_the_date() {
|
||||
assert_eq!(release_year(" 1977-10-28 "), Some("1977"));
|
||||
assert_eq!(release_year("1977/10/28"), Some("1977"));
|
||||
assert_eq!(release_year("19771028"), Some("1977"));
|
||||
}
|
||||
|
||||
#[cfg(feature = "notifications")]
|
||||
#[test]
|
||||
fn notification_without_an_album_is_just_the_track() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue