Skip to content

Commit

Permalink
added Read All button, counter fixes, light optimization
Browse files Browse the repository at this point in the history
  • Loading branch information
dhonus committed Mar 5, 2023
1 parent 21bc1d7 commit 3a57792
Show file tree
Hide file tree
Showing 10 changed files with 208 additions and 33 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This is a simple RSS reader that I made to learn Rust and Tauri. I wanted something quite simple to use every day to read my feeds. Does not cache images, online only.

![img](screen.png)
![img](screenshot.png)

## How to use
You can download a prebuilt binary from the [releases](https://github.com/dhonus/arcanum/releases) page. Only linux tested.
Expand Down
61 changes: 61 additions & 0 deletions public/iconmonstr-eye-check-lined.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed screen.png
Binary file not shown.
Binary file added screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 12 additions & 7 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ fn mark_read(url: &str, guid: &str){

#[tauri::command]
fn update_feed(url: &str) -> Result<HashMap<String, Vec<FeedMeta>>, String> {
println!("Updating {}", url);

routes::rss::update(url);

let data = routes::rss::main( "", "");
Expand All @@ -37,10 +35,20 @@ fn update_feed(url: &str) -> Result<HashMap<String, Vec<FeedMeta>>, String> {
}
}

#[tauri::command]
fn read_feed(url: &str) -> Result<HashMap<String, Vec<FeedMeta>>, String> {
routes::rss::read(url);

let data = routes::rss::main( "", "");
match data {
Some(feeds) => Ok(feeds.clone()),
_ => Err("Failed to parse the feed. Please verify the URL is correct.".to_string()),
}
}

#[tauri::command]
fn update_all() -> Result<HashMap<String, Vec<FeedMeta>>, String> {
routes::rss::update_all();
println!("Updating all feeds");
let data = routes::rss::main("", "");
match data {
Some(feeds) => Ok(feeds.clone()),
Expand All @@ -50,10 +58,7 @@ fn update_all() -> Result<HashMap<String, Vec<FeedMeta>>, String> {

#[tauri::command]
fn delete_feed(url: &str) -> Result<HashMap<String, Vec<FeedMeta>>, String> {
println!("Deleting {}", url);

routes::rss::delete(url);

let data = routes::rss::main( "", "");
match data {
Some(feeds) => Ok(feeds.clone()),
Expand All @@ -63,7 +68,7 @@ fn delete_feed(url: &str) -> Result<HashMap<String, Vec<FeedMeta>>, String> {

fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![feed, mark_read, update_feed, update_all, delete_feed])
.invoke_handler(tauri::generate_handler![feed, mark_read, update_feed, read_feed, update_all, delete_feed])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
14 changes: 11 additions & 3 deletions src-tauri/src/routes/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,15 @@ pub async fn pull(url: &str, filename: &str, client: &Client) -> Result<(), Stri

pub fn parse(file: String) -> Channel {
let xmlfile = File::open(file.clone()).unwrap();
let channel = Channel::read_from(BufReader::new(xmlfile)).unwrap();
//println!("Channel: {:?}", channel);
return channel;
let channel = Channel::read_from(BufReader::new(xmlfile));
return match channel {
Ok(channel) => channel,
Err(err) => {
let mut bad_channel = Channel::default();
bad_channel.title = "Error parsing".to_string();
bad_channel.description = format!("{} cannot be parsed because: {}. To fix, try re-adding the feed, or checking the source website for errors.", file, err).to_string();
bad_channel
}
}

}
56 changes: 56 additions & 0 deletions src-tauri/src/routes/rss.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,26 @@ impl FeedMeta {
Ok(lines)
}
// take guid and save into lof of read articles
fn re_index_and_mark_all_read(filename: &str, lines: &mut FeedMeta) -> Result<(), std::io::Error> {
println!("{} is the filename", filename);
let mut file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(filename)?;

file.set_len(0)?;
file.seek(SeekFrom::Start(0))?;
let mut writer = std::io::BufWriter::new(&file);
for line in lines.feed.items.clone() {
writer.write(line.guid.unwrap().value.as_bytes())?;
writer.write(b"\n")?;
}
writer.flush().unwrap();

Ok(())
}

fn modify_file(filename: &str, adding: &str) -> Result<(), std::io::Error> {
// Open the file for reading or create it if it doesn't exist
let mut file = OpenOptions::new()
Expand Down Expand Up @@ -264,6 +284,42 @@ pub fn update_all() {
println!("Saved.");
}

pub fn read(source: &str) {
let mut feeds: Vec<FeedMeta> = FeedMeta::load();
if feeds.len() == 0 {
println!("No feeds");
return;
}
let mut index = 0;
for (i, feed) in feeds.iter().enumerate() {
if feed.filename == source {
index = i;
}
}
let runtime = tokio::runtime::Runtime::new().unwrap();

let client = reqwest::Client::builder()
.gzip(true)
.timeout(Duration::from_secs(8))
.build().unwrap();
let feed = &mut feeds[index];

match runtime.block_on(parser::pull(feed.url.as_str(), feed.filename.as_str(), &client)) {
Ok(_) => {
println!("Updated {}", feed.filename);
}
Err(e) => {
println!("Error updating {}: {}", feed.filename, e);
}
}

let filename = format!("{}.log", source);
FeedMeta::re_index_and_mark_all_read(filename.as_str(), feed).unwrap();

FeedMeta::save(feeds);
println!("Saved.");
}

pub fn delete(source: &str) {
let mut feeds: Vec<FeedMeta> = FeedMeta::load();
let mut index = 0;
Expand Down
12 changes: 6 additions & 6 deletions src/lib/CollapsibleSection.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@
margin: 0!important;
}
div.collapsible {
padding: .3rem;
padding: 0 .3rem;
}
button {
display: flex;
justify-content: left;
align-items: center;
gap: .6rem;
margin: 0;
margin: .3rem 0;
padding: .6rem 0.5rem;
background: none;
color: whitesmoke;
Expand All @@ -44,10 +44,10 @@
border: 1px solid transparent;
}
button:hover {
background: #2f2f2f;
border: 1px solid #3d3d3d;
box-shadow: 0 0 5px 1px #1c1c1c;
cursor: pointer;
background: #2f2f2f;
border: 1px solid #3d3d3d!important;
box-shadow: 0 0 5px 1px #1c1c1c;
cursor: pointer;
}
button img{
Expand Down
46 changes: 35 additions & 11 deletions src/lib/Home.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
}
import { writable } from 'svelte/store';
const readBuffer = writable([]);
const readDict = writable({});
let readBuffer = writable([]);
let readDict = writable({});
let readBufferValue = [];
let readDictValue = {};
Expand Down Expand Up @@ -54,7 +54,10 @@
warning = "Please enter a valid URL starting with http!";
return;
}
let __feeds__ = await invoke("feed", { url, category });
let __feeds__ = await invoke("feed", { url, category }).catch((e) => {
console.log(e);
warning = e;
});
console.log(__feeds__);
feeds = __feeds__;
url = "";
Expand All @@ -77,13 +80,25 @@
}
}
async function updateFeed(url){
console.log(url, "is the thing");
let __feeds__ = await invoke("update_feed", { url }).catch((e) => {
console.log(e);
});
feeds = __feeds__;
await loadFeed(url);
console.log(__feeds__);
readBuffer.set([]);
readDict.set({});
}
async function readFeed(url){
let __feeds__ = await invoke("read_feed", { url }).catch((e) => {
console.log(e);
});
feeds = __feeds__;
await loadFeed(url);
console.log(__feeds__);
readBuffer.set([]);
readDict.set({});
}
async function updateAll(){
Expand Down Expand Up @@ -175,8 +190,10 @@
<img src="/spinner.gif"/>
{/if}
</div>

<button on:click={updateAll} class="update_button">Update feeds</button>
<button on:click={updateAll} class="update_button">
<img src="/iconmonstr-refresh-lined.svg" />
<p>Update feeds</p>
</button>
</div>
{#each Object.entries(feeds) as [key, category]}
<CollapsibleSection headerText={key} >
Expand All @@ -200,12 +217,19 @@
{currentFeed.description}
</div>
<div class="meta-control">
<span>
<button class="update"
on:click={updateFeed(currentFeed.filename)} title="Update feed">
<img src="/iconmonstr-refresh-lined.svg" />
<p>Update</p>
</button>
<button class="update"
on:click={readFeed(currentFeed.filename)} title="Mark all as read">
<img src="/iconmonstr-eye-check-lined.svg" />
</button>
</span>
<button class="update"
on:click={updateFeed(currentFeed.filename)}>
<img src="/iconmonstr-refresh-lined.svg" />
</button>
<button class="update"
on:click={deleteFeed(currentFeed.filename)}>
on:click={deleteFeed(currentFeed.filename)} title="Delete feed">
<img src="/iconmonstr-trash-can-28.svg" />
</button>
</div>
Expand Down
Loading

0 comments on commit 3a57792

Please sign in to comment.