forked from Morganamilo/paru
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnews.rs
124 lines (104 loc) · 3.12 KB
/
news.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use crate::config::Config;
use crate::fmt::print_indent;
use std::str::Chars;
use ansiterm::Style;
use anyhow::{bail, Result};
use htmlescape::decode_html;
use rss::Channel;
use tr::tr;
enum Tag {
CodeOpen,
CodeClose,
PClose,
Other,
}
pub fn newest_pkg(config: &Config) -> i64 {
let max = config
.alpm
.localdb()
.pkgs()
.iter()
.map(|p| p.build_date())
.max()
.unwrap_or_default();
max
}
pub async fn news(config: &Config) -> Result<i32> {
let url = config.arch_url.join("feeds/news")?;
let client = config.raur.client();
let resp = client.get(url.clone()).send().await?;
if !resp.status().is_success() {
bail!("{}: {}", url, resp.status());
}
let bytes = resp.bytes().await?;
let channel = Channel::read_from(bytes.as_ref())?;
let c = config.color;
let mut printed = false;
for item in channel.into_items().into_iter().rev() {
let date = item.pub_date().unwrap_or_default();
match chrono::DateTime::parse_from_rfc2822(date) {
Ok(date) => {
if config.news < 2 && date.timestamp() < newest_pkg(config) {
continue;
}
print!("{} ", c.news_date.paint(date.format("%F").to_string()));
}
Err(_) => print!("{}", tr!("No Date ")),
}
let no_title = tr!("No Title");
let title = item.title().unwrap_or(no_title.as_str());
println!("{}", c.bold.paint(title));
printed = true;
parse_html(config, item.description().unwrap_or_default());
}
if !printed {
eprintln!("{}", tr!("no new news"));
Ok(1)
} else {
Ok(0)
}
}
fn parse_html(config: &Config, html: &str) {
let code = config.color.code;
let mut words = String::with_capacity(html.len());
let mut chars = html.chars();
while let Some(c) = chars.next() {
if c == '<' {
let tag = parse_tag(&mut chars);
match tag {
Tag::CodeOpen => {
words.push(' ');
words.push_str(&code.prefix().to_string());
}
Tag::CodeClose => words.push_str(&code.suffix().to_string()),
Tag::PClose => words.push('\n'),
Tag::Other => (),
}
} else {
words.push(c);
}
}
words.push_str(&code.suffix().to_string());
let words = words;
let words = decode_html(&words).unwrap_or(words);
for line in words.lines() {
print!(" ");
let line = line.split_whitespace();
print_indent(Style::new(), 4, 4, config.cols, " ", line);
}
}
fn parse_tag(iter: &mut Chars) -> Tag {
if iter.as_str().starts_with("code>") {
iter.by_ref().take(5).count();
Tag::CodeOpen
} else if iter.as_str().starts_with("/code>") {
iter.by_ref().take(6).count();
Tag::CodeClose
} else if iter.as_str().starts_with("/p>") {
iter.by_ref().take(3).count();
Tag::PClose
} else {
iter.by_ref().any(|c| c == '>');
Tag::Other
}
}