spotify_cli/io/formatters/
chapter.rs1use serde_json::Value;
4
5use crate::io::common::{DurationFormat, format_duration_as};
6
7pub fn format_chapter_detail(payload: &Value) {
8 let name = payload
9 .get("name")
10 .and_then(|v| v.as_str())
11 .unwrap_or("Unknown");
12 let audiobook_name = payload
13 .get("audiobook")
14 .and_then(|a| a.get("name"))
15 .and_then(|v| v.as_str())
16 .unwrap_or("Unknown");
17 let description = payload
18 .get("description")
19 .and_then(|v| v.as_str())
20 .unwrap_or("");
21 let duration_ms = payload
22 .get("duration_ms")
23 .and_then(|v| v.as_u64())
24 .unwrap_or(0);
25 let chapter_number = payload.get("chapter_number").and_then(|v| v.as_u64());
26 let uri = payload.get("uri").and_then(|v| v.as_str()).unwrap_or("");
27
28 println!("{}", name);
29 println!(" Audiobook: {}", audiobook_name);
30 if let Some(num) = chapter_number {
31 println!(" Chapter: {}", num);
32 }
33 println!(
34 " Duration: {}",
35 format_duration_as(duration_ms, DurationFormat::LongWithSeconds)
36 );
37 if !description.is_empty() {
38 let desc = if description.len() > 200 {
39 format!("{}...", &description[..200])
40 } else {
41 description.to_string()
42 };
43 println!(" Description: {}", desc);
44 }
45 if !uri.is_empty() {
46 println!(" URI: {}", uri);
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53 use serde_json::json;
54
55 #[test]
56 fn format_chapter_detail_full() {
57 let payload = json!({
58 "name": "Chapter 1: The Beginning",
59 "audiobook": { "name": "Great Audiobook" },
60 "description": "In this chapter we explore the beginning",
61 "duration_ms": 1800000,
62 "chapter_number": 1,
63 "uri": "spotify:chapter:abc123"
64 });
65 format_chapter_detail(&payload);
66 }
67
68 #[test]
69 fn format_chapter_detail_minimal() {
70 let payload = json!({});
71 format_chapter_detail(&payload);
72 }
73
74 #[test]
75 fn format_chapter_detail_long_description() {
76 let long_desc = "A".repeat(300);
77 let payload = json!({
78 "name": "Chapter",
79 "audiobook": { "name": "Book" },
80 "description": long_desc,
81 "duration_ms": 600000
82 });
83 format_chapter_detail(&payload);
84 }
85
86 #[test]
87 fn format_chapter_detail_no_chapter_number() {
88 let payload = json!({
89 "name": "Prologue",
90 "audiobook": { "name": "Mystery Book" },
91 "duration_ms": 300000
92 });
93 format_chapter_detail(&payload);
94 }
95
96 #[test]
97 fn format_chapter_detail_short_duration() {
98 let payload = json!({
99 "name": "Short Chapter",
100 "duration_ms": 45000,
101 "chapter_number": 5
102 });
103 format_chapter_detail(&payload);
104 }
105
106 #[test]
107 fn format_chapter_detail_no_uri() {
108 let payload = json!({
109 "name": "Chapter Without URI",
110 "audiobook": { "name": "Book" },
111 "duration_ms": 900000
112 });
113 format_chapter_detail(&payload);
114 }
115}