diff --git a/Cargo.toml b/Cargo.toml index 2f0d932..0d468d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ directories = "6.0.0" chrono = "0.4.41" rss_content = { git = "https://code.gabe.rocks/gabriel/rss_content", version = "0.1.1" } url = "2.5.4" +opml = "1.1.6" #rfd = "0.15.4" (for importing files) [profile.dev] debug=true diff --git a/src/db.rs b/src/db.rs index 874b24b..445947b 100644 --- a/src/db.rs +++ b/src/db.rs @@ -2,6 +2,7 @@ use super::files::*; use super::net::*; use chrono::DateTime; use chrono::Utc; +use rss::Channel; use rusqlite::Row; //Maybe use a different time? use rusqlite::{Connection, Result}; @@ -100,7 +101,17 @@ pub fn get_feed_id_by_url(url: &str) -> Option { } } pub fn add_feed(url: &str) -> Option { - let feed = load_rss(url).unwrap(); + let mut feed: Channel; + match load_rss(url) { + Some(f) => { + feed = f; + } + None => { + return None; + } + + + } let time = Utc::now().to_rfc2822(); let image = if let Some(i) = feed.image() { i.url().to_owned() diff --git a/src/files.rs b/src/files.rs index 5162a42..fa327ae 100644 --- a/src/files.rs +++ b/src/files.rs @@ -21,4 +21,4 @@ pub fn get_cache_directory() -> std::path::PathBuf { }; dirs.config_dir().to_owned() -} +} \ No newline at end of file diff --git a/src/net.rs b/src/net.rs index ad60100..b602a00 100644 --- a/src/net.rs +++ b/src/net.rs @@ -29,7 +29,9 @@ pub fn url_network(url: &str) -> Network { return Network::Clearnet; } } - None => {return Network::Unknown;} + None => { + return Network::Unknown; + } }, Err(e) => { return Network::Clearnet; @@ -39,7 +41,7 @@ pub fn url_network(url: &str) -> Network { } #[test] -fn network_testing(){ +fn network_testing() { assert!(url_network("http://gabe.onion/rss") == Network::Tor); assert!(url_network("http://gabe.i2p/rss") == Network::I2P); assert!(url_network("https://gabe.rocks/rss") == Network::Clearnet); @@ -96,6 +98,36 @@ fn get_content(url: &str) -> Option { } } +pub fn retrieve_opml(url: &str) -> Vec { + match get_content(url) { + Some(c) => match opml::OPML::from_str(&c) { + Ok(list) => { + let mut links = Vec::new(); + for link in list.body.outlines { + match link.html_url { + Some(l) => match Url::parse(&l) { + Ok(u) => { + links.push(u); + } + Err(_) => {} + }, + None => {} + } + } + return links; + } + Err(e) => { + println!("Failed to parse OPML: {}\n{}", c, e); + return Vec::new(); + } + }, + None => { + return Vec::new(); + } + } + todo!() +} + #[test] fn get_onion_content() { get_content("http://gabriel262me3lgv3w7xohtesg3laoojmtye644pwirhdm73qmedmsqd.onion/rss"); @@ -147,7 +179,8 @@ pub fn load_rss(url: &str) -> Option { } }, Err(err) => { - panic!("Error loading feed.:{}", err) + println!("Error loading feed.:{}", err); + return None; } } } @@ -202,7 +235,6 @@ fn is_media(link: &str) -> bool { false } - pub fn parse_links(content: &str) -> Vec { let mut result = Vec::new(); let frag = Html::parse_fragment(content); @@ -218,4 +250,4 @@ pub fn parse_links(content: &str) -> Vec { } } result -} \ No newline at end of file +} diff --git a/src/ui.rs b/src/ui.rs index a0ef63b..af2354b 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,4 +1,5 @@ use crate::db::FeedItem; +use crate::net; use crate::widgets::content_view; use crate::widgets::media_view; use crate::widgets::navbar; @@ -16,6 +17,7 @@ use iced::{ }; use rss_content::parse_content; use rss_content::Content; +use url::Url; const ICON: &[u8] = include_bytes!("../assets/icon_placeholder.png"); pub fn user_interface() -> iced::Result { @@ -69,6 +71,7 @@ pub enum Message { AddFeed(String), RemoveFeed(usize), LoadItem(usize), + ProcessOPML(String), FieldUpdated(AppField, String), LinkClicked(String), Done(String), @@ -78,6 +81,18 @@ pub enum Message { #[derive(Debug, Clone)] pub enum AppField { FeedInput, + OPMLInput, +} + + +async fn add_multiple_feeds_background(url:String) -> String { + println!("Adding feeds."); + let links = net::retrieve_opml(&url); + for link in links { + add_feed_background(link.to_string()).await; + } + "Done adding feeds.".to_string() + } async fn add_feed_background(url: String) -> String { @@ -102,6 +117,11 @@ fn update(state: &mut State, mes: Message) -> Task { state.page = Page::FeedView; Task::none() } + + Message::ProcessOPML(url) => { + state.feed_input = "".to_string(); + Task::perform(add_multiple_feeds_background(url), Message::Done) + } Message::AddFeed(f) => { state.feed_input = "".to_string(); @@ -138,6 +158,9 @@ fn update(state: &mut State, mes: Message) -> Task { match field { AppField::FeedInput => { state.feed_input = value; + }, + AppField::OPMLInput => { + state.feed_input = value; } } Task::none() @@ -203,6 +226,7 @@ fn item_view(state: &State) -> Element<'_, Message> { }; container(column!( widgets::navbar(state), + text(title).size(34), media_view(state), content_view(state), )) @@ -249,6 +273,12 @@ fn testing(state: &State) -> Element<'_, Message> { ) .spacing(5) .padding(10), + row!( + text_input("OPML Url",&state.feed_input) + .on_input(|val| Message::FieldUpdated(AppField::OPMLInput,val)) + .width(300), + button("Add feeds from .OPML").on_press(Message::ProcessOPML(state.feed_input.clone())) + ), button("Wipe DB").on_press(Message::ResetDB), button("go back!").on_press(Message::ChangePage(Page::Home)) )