use serde::{Deserialize, Serialize};
use crate::{command, lyrics::Lyrics};
#[derive(Clone, Debug)]
pub struct Song {
pub data: SongData,
pub lyrics: Option<Lyrics>,
}
impl Song {
pub fn new(data: SongData, lyrics: Option<Lyrics>) -> Self {
Song {
data,
lyrics,
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct SongData {
pub title: String,
pub artist: Option<String>,
pub album: Option<String>,
pub duration: Option<f64>,
pub player: Option<Player>,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub enum Player {
Spotify
}
impl ToString for Player {
fn to_string(&self) -> String {
match self {
Self::Spotify => "spotify"
}.to_string()
}
}
pub fn get_flag_from_player(player: &Option<Player>) -> String {
if let Some(player) = &player {
format!("-p {}", player.to_string())
} else { "".to_string() }
}
impl SongData {
pub fn get_data() -> Option<Self> {
let spotify_data = SongData::get_data_from_player(Some(Player::Spotify));
spotify_data.or(SongData::get_data_from_player(None))
}
pub fn get_title_truncated(&self, max_length: usize) -> String {
if self.title.len() <= max_length {
self.title.clone()
} else {
format!("{}...", self.title.chars().take(max_length).collect::<String>())
}
}
fn get_data_from_player(player: Option<Player>) -> Option<Self> {
let flag = get_flag_from_player(&player);
let metadata_command = format!("playerctl {flag} metadata ");
let get_attr = |name: &str|
Some(
command(&(metadata_command.clone() + name)).trim().to_string(),
).filter(|s| !s.is_empty());
let title = get_attr("title")?;
let artist = get_attr("artist");
let album = get_attr("album");
let duration = get_attr("mpris:length")
.map(|d| d.parse::<f64>())
.and_then(|result| result.ok())
.map(|d| d / 1e6);
Some(Self {
title,
artist,
album,
duration,
player,
})
}
}