1use serde::{Deserialize, Serialize};
2use crate::songrec::RecognitionResult;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub enum OutputFormat {
7 Simple,
9 Json,
11 Csv,
13 Custom(&'static str),
15}
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct RecognitionOutput {
20 pub format: String,
21 pub content: String,
22 pub timestamp: chrono::DateTime<chrono::Utc>,
23}
24
25impl RecognitionOutput {
26 pub fn format_result(result: &RecognitionResult, format: OutputFormat) -> Self {
28 let content = match format {
29 OutputFormat::Simple => {
30 format!("{} - {}", result.artist_name, result.song_name)
31 },
32 OutputFormat::Json => {
33 serde_json::to_string(&result).unwrap_or_else(|_| "{}".to_string()) },
35 OutputFormat::Csv => {
36 format!(
37 "\"{}\",\"{}\",\"{}\",\"{}\",\"{}\",\"{}\"",
38 result.song_name,
39 result.artist_name,
40 result.album_name.as_deref().unwrap_or(""),
41 result.release_year.as_deref().unwrap_or(""),
42 result.genre.as_deref().unwrap_or(""),
43 result.recognition_timestamp.format("%Y-%m-%d %H:%M:%S UTC")
44 )
45 },
46 OutputFormat::Custom(template) => {
47 Self::format_custom(result, template)
48 },
49 };
50
51 RecognitionOutput {
52 format: format.to_string(),
53 content,
54 timestamp: chrono::Utc::now(),
55 }
56 }
57
58 fn format_custom(result: &RecognitionResult, template: &str) -> String {
60 template
61 .replace("{song}", &result.song_name)
62 .replace("{artist}", &result.artist_name)
63 .replace("{album}", result.album_name.as_deref().unwrap_or("Unknown"))
64 .replace("{year}", result.release_year.as_deref().unwrap_or("Unknown"))
65 .replace("{genre}", result.genre.as_deref().unwrap_or("Unknown"))
66 .replace("{timestamp}", &result.recognition_timestamp.format("%Y-%m-%d %H:%M:%S UTC").to_string())
67 }
68
69 pub fn csv_header() -> &'static str {
71 "\"Song\",\"Artist\",\"Album\",\"Year\",\"Genre\",\"Timestamp\""
72 }
73}
74
75impl std::fmt::Display for RecognitionOutput {
76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 write!(f, "{}", self.content)
78 }
79}
80
81impl std::fmt::Display for OutputFormat {
82 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83 match self {
84 OutputFormat::Simple => write!(f, "Simple"),
85 OutputFormat::Json => write!(f, "Json"),
86 OutputFormat::Csv => write!(f, "Csv"),
87 OutputFormat::Custom(template) => write!(f, "Custom({})", template),
88 }
89 }
90}