Initial commit

This commit is contained in:
Andrew Pamment 2025-09-06 23:29:22 +00:00
commit 0e9aac214c
4 changed files with 1982 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target/

1825
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

11
Cargo.toml Normal file
View File

@ -0,0 +1,11 @@
[package]
name = "rssreader"
version = "0.1.0"
edition = "2024"
[dependencies]
rss = "2.0"
doorlib = { git = "https://git.quinnos.com/apamment/doorlib" }
reqwest = { version = "0.12.23", features = ["blocking"] }
textwrap = "0.16.2"
iconv-native = { version = "0.1.0", default-features = false, features = ["libiconv"] }

145
src/main.rs Normal file
View File

@ -0,0 +1,145 @@
use doorlib::{self as door, esc, Conn};
use std::error::Error;
use rss::Channel;
use std::fmt::Write;
use textwrap::wrap;
use iconv_native::convert;
use std::fs::File;
use std::io::BufReader;
fn report(mut err: &(dyn std::error::Error + 'static)) -> String {
let mut s = format!("{}", err);
while let Some(src) = err.source() {
let _ = write!(s, "\r\n\r\nCaused by: {}", src);
err = src;
}
s
}
fn xbit_news_feed() -> Result<Channel, Box<dyn Error>> {
let resp = reqwest::blocking::get("https://x-bit.org/rss/rss.xml");
match resp {
Ok(resp) => {
if resp.status().is_success() {
let content = resp.bytes()?;
let channel = Channel::read_from(&content[..])?;
return Ok(channel);
}
},
Err(e) => {
report(e.source().expect("REASON"));
}
}
Err("Error loading feed".into())
}
fn door_main(mut u: door::User) -> Result<(), Box<dyn Error>> {
let file = File::open("rss.xml").unwrap();
let channel = Channel::read_from(BufReader::new(file)).unwrap();
//let channel = xbit_news_feed()?;
let mut index = 0;
let mut start = 0;
u.write_str(format!("{}{}{} {}{}{}", esc!("[2J"), esc!("[1;1H"), esc!("[0;30;46m"), channel.title(), esc!("[K"), esc!("[0m")).as_str())?;
u.write_str(format!("{}{} Press Q to quit, Up and Down to Scroll {}{}", esc!("[24;1H"), esc!("[0;30;46m"), esc!("[K"), esc!("[0m")).as_str())?;
loop {
for i in start..start + 22 {
let p = format!("\x1b[{};1H", (i - start) + 2);
if i < channel.items().len() {
if i == index {
u.write_ln(format!("{}{}{:62.62} {:16.16}{}{}", p, esc!("[1;37;45m"), String::from_utf8(convert(channel.items[i].title().unwrap_or("No Title"), "UTF-8", "ASCII//TRANSLIT").unwrap_or(channel.items[i].title().unwrap_or("No Title").into()))?, channel.items[i].pub_date().unwrap_or("??/??/????"), esc!("[K"), esc!("[0m")).as_str())?;
} else {
u.write_ln(format!("{}{}{:62.62} {:16.16}{}{}", p, esc!("[1;37m"), String::from_utf8(convert(channel.items[i].title().unwrap_or("No Title"), "UTF-8", "ASCII//TRANSLIT").unwrap_or(channel.items[i].title().unwrap_or("No Title").into()))?, channel.items[i].pub_date().unwrap_or("??/??/????"), esc!("[K"), esc!("[0m")).as_str())?;
}
} else {
u.write_ln(format!("{}{}", p, esc!("[K")).as_str())?;
}
}
let mut ch = u.read_byte()?;
if ch == b'\x1b' {
ch = u.read_byte()?;
if ch == b'[' {
ch = u.read_byte()?;
if ch == b'A' {
if index > 0 {
index -= 1;
if index < start {
start -= 22;
}
}
} else if ch == b'B' {
if !channel.items().is_empty() && index < channel.items().len() - 1 {
index += 1;
if index >= start + 22 {
start += 22;
}
}
}
}
} else if ch == b'q' || ch == b'Q' {
break;
} else if ch == b'\n' || ch == b'\r' {
let desc = String::from_utf8(convert(channel.items[index].description().unwrap_or("No Content"), "UTF-8", "ASCII//TRANSLIT").unwrap_or(channel.items[index].description().unwrap_or("No Content").into()))?;
let content = wrap(&desc, 79);
let mut cstart = 0;
let mut cindex = 0;
loop {
u.write_ln(format!("{}{}{}{}{}{}", esc!("[2J"), esc!("[1;1H"), esc!("[0;30;46m"), channel.items[index].title().unwrap_or("No Title"), esc!("[K"), esc!("[0m")).as_str())?;
u.write_ln(format!("{}{}{}{}{}", esc!("[2;1H"), esc!("[0;30;46m"), channel.items[index].link().unwrap_or("No Link"), esc!("[K"), esc!("[0m")).as_str())?;
u.write_str(format!("{}{} Press ENTER to Return to menu, Up and Down to Scroll {}{}", esc!("[24;1H"), esc!("[0;30;46m"), esc!("[K"), esc!("[0m")).as_str())?;
for i in cstart..cstart+20 {
let p = format!("\x1b[{};1H", (i - cstart) + 3);
if i < content.len() {
u.write_ln(format!("{}{}{}", p, &content[i], esc!("[K")).as_str())?;
} else {
u.write_ln(format!("{}{}", p, esc!("[K")).as_str())?;
}
}
ch = u.read_byte()?;
if ch == b'\n' || ch == b'\r' || ch == b'q' || ch == b'Q' {
break;
} else if ch == b'\x1b' {
ch = u.read_byte()?;
if ch == b'[' {
ch = u.read_byte()?;
if ch == b'A' {
if cindex > 0 {
cindex -= 20;
if cindex < cstart {
cstart -= 20;
}
}
} else if ch == b'B' {
if !content.is_empty() && cindex + 20 < content.len() {
cindex += 20;
if cindex >= cstart + 20 {
cstart += 20;
}
}
}
}
}
}
u.write_str(format!("{}{}{} {}{}{}", esc!("[2J"), esc!("[1;1H"), esc!("[0;30;46m"), String::from_utf8(convert(channel.title(), "UTF-8", "ASCII//TRANSLIT").unwrap_or(channel.title().into()))?, esc!("[K"), esc!("[0m")).as_str())?;
u.write_str(format!("{}{} Press Q to quit, Up and Down to Scroll {}{}", esc!("[24;1H"), esc!("[0;30;46m"), esc!("[K"), esc!("[0m")).as_str())?;
}
}
Ok(())
}
fn main() {
let u = door::init().unwrap();
let _ = door_main(u);
}