Lazy implementation of .opml import. Needs cleanup and better streamlining of events.
This commit is contained in:
parent
60fd547a6d
commit
8dbda35b18
5 changed files with 81 additions and 7 deletions
|
|
@ -13,6 +13,7 @@ directories = "6.0.0"
|
||||||
chrono = "0.4.41"
|
chrono = "0.4.41"
|
||||||
rss_content = { git = "https://code.gabe.rocks/gabriel/rss_content", version = "0.1.1" }
|
rss_content = { git = "https://code.gabe.rocks/gabriel/rss_content", version = "0.1.1" }
|
||||||
url = "2.5.4"
|
url = "2.5.4"
|
||||||
|
opml = "1.1.6"
|
||||||
#rfd = "0.15.4" (for importing files)
|
#rfd = "0.15.4" (for importing files)
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
debug=true
|
debug=true
|
||||||
|
|
|
||||||
13
src/db.rs
13
src/db.rs
|
|
@ -2,6 +2,7 @@ use super::files::*;
|
||||||
use super::net::*;
|
use super::net::*;
|
||||||
use chrono::DateTime;
|
use chrono::DateTime;
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
|
use rss::Channel;
|
||||||
use rusqlite::Row;
|
use rusqlite::Row;
|
||||||
//Maybe use a different time?
|
//Maybe use a different time?
|
||||||
use rusqlite::{Connection, Result};
|
use rusqlite::{Connection, Result};
|
||||||
|
|
@ -100,7 +101,17 @@ pub fn get_feed_id_by_url(url: &str) -> Option<usize> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn add_feed(url: &str) -> Option<usize> {
|
pub fn add_feed(url: &str) -> Option<usize> {
|
||||||
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 time = Utc::now().to_rfc2822();
|
||||||
let image = if let Some(i) = feed.image() {
|
let image = if let Some(i) = feed.image() {
|
||||||
i.url().to_owned()
|
i.url().to_owned()
|
||||||
|
|
|
||||||
40
src/net.rs
40
src/net.rs
|
|
@ -29,7 +29,9 @@ pub fn url_network(url: &str) -> Network {
|
||||||
return Network::Clearnet;
|
return Network::Clearnet;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {return Network::Unknown;}
|
None => {
|
||||||
|
return Network::Unknown;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Network::Clearnet;
|
return Network::Clearnet;
|
||||||
|
|
@ -39,7 +41,7 @@ pub fn url_network(url: &str) -> Network {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn network_testing(){
|
fn network_testing() {
|
||||||
assert!(url_network("http://gabe.onion/rss") == Network::Tor);
|
assert!(url_network("http://gabe.onion/rss") == Network::Tor);
|
||||||
assert!(url_network("http://gabe.i2p/rss") == Network::I2P);
|
assert!(url_network("http://gabe.i2p/rss") == Network::I2P);
|
||||||
assert!(url_network("https://gabe.rocks/rss") == Network::Clearnet);
|
assert!(url_network("https://gabe.rocks/rss") == Network::Clearnet);
|
||||||
|
|
@ -96,6 +98,36 @@ fn get_content(url: &str) -> Option<String> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn retrieve_opml(url: &str) -> Vec<Url> {
|
||||||
|
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]
|
#[test]
|
||||||
fn get_onion_content() {
|
fn get_onion_content() {
|
||||||
get_content("http://gabriel262me3lgv3w7xohtesg3laoojmtye644pwirhdm73qmedmsqd.onion/rss");
|
get_content("http://gabriel262me3lgv3w7xohtesg3laoojmtye644pwirhdm73qmedmsqd.onion/rss");
|
||||||
|
|
@ -147,7 +179,8 @@ pub fn load_rss(url: &str) -> Option<Channel> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(err) => {
|
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
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn parse_links(content: &str) -> Vec<String> {
|
pub fn parse_links(content: &str) -> Vec<String> {
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
let frag = Html::parse_fragment(content);
|
let frag = Html::parse_fragment(content);
|
||||||
|
|
|
||||||
30
src/ui.rs
30
src/ui.rs
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::db::FeedItem;
|
use crate::db::FeedItem;
|
||||||
|
use crate::net;
|
||||||
use crate::widgets::content_view;
|
use crate::widgets::content_view;
|
||||||
use crate::widgets::media_view;
|
use crate::widgets::media_view;
|
||||||
use crate::widgets::navbar;
|
use crate::widgets::navbar;
|
||||||
|
|
@ -16,6 +17,7 @@ use iced::{
|
||||||
};
|
};
|
||||||
use rss_content::parse_content;
|
use rss_content::parse_content;
|
||||||
use rss_content::Content;
|
use rss_content::Content;
|
||||||
|
use url::Url;
|
||||||
const ICON: &[u8] = include_bytes!("../assets/icon_placeholder.png");
|
const ICON: &[u8] = include_bytes!("../assets/icon_placeholder.png");
|
||||||
|
|
||||||
pub fn user_interface() -> iced::Result {
|
pub fn user_interface() -> iced::Result {
|
||||||
|
|
@ -69,6 +71,7 @@ pub enum Message {
|
||||||
AddFeed(String),
|
AddFeed(String),
|
||||||
RemoveFeed(usize),
|
RemoveFeed(usize),
|
||||||
LoadItem(usize),
|
LoadItem(usize),
|
||||||
|
ProcessOPML(String),
|
||||||
FieldUpdated(AppField, String),
|
FieldUpdated(AppField, String),
|
||||||
LinkClicked(String),
|
LinkClicked(String),
|
||||||
Done(String),
|
Done(String),
|
||||||
|
|
@ -78,6 +81,18 @@ pub enum Message {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum AppField {
|
pub enum AppField {
|
||||||
FeedInput,
|
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 {
|
async fn add_feed_background(url: String) -> String {
|
||||||
|
|
@ -103,6 +118,11 @@ fn update(state: &mut State, mes: Message) -> Task<Message> {
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Message::ProcessOPML(url) => {
|
||||||
|
state.feed_input = "".to_string();
|
||||||
|
Task::perform(add_multiple_feeds_background(url), Message::Done)
|
||||||
|
}
|
||||||
|
|
||||||
Message::AddFeed(f) => {
|
Message::AddFeed(f) => {
|
||||||
state.feed_input = "".to_string();
|
state.feed_input = "".to_string();
|
||||||
Task::perform(add_feed_background(f.to_string()), Message::Done)
|
Task::perform(add_feed_background(f.to_string()), Message::Done)
|
||||||
|
|
@ -138,6 +158,9 @@ fn update(state: &mut State, mes: Message) -> Task<Message> {
|
||||||
match field {
|
match field {
|
||||||
AppField::FeedInput => {
|
AppField::FeedInput => {
|
||||||
state.feed_input = value;
|
state.feed_input = value;
|
||||||
|
},
|
||||||
|
AppField::OPMLInput => {
|
||||||
|
state.feed_input = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Task::none()
|
Task::none()
|
||||||
|
|
@ -203,6 +226,7 @@ fn item_view(state: &State) -> Element<'_, Message> {
|
||||||
};
|
};
|
||||||
container(column!(
|
container(column!(
|
||||||
widgets::navbar(state),
|
widgets::navbar(state),
|
||||||
|
text(title).size(34),
|
||||||
media_view(state),
|
media_view(state),
|
||||||
content_view(state),
|
content_view(state),
|
||||||
))
|
))
|
||||||
|
|
@ -249,6 +273,12 @@ fn testing(state: &State) -> Element<'_, Message> {
|
||||||
)
|
)
|
||||||
.spacing(5)
|
.spacing(5)
|
||||||
.padding(10),
|
.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("Wipe DB").on_press(Message::ResetDB),
|
||||||
button("go back!").on_press(Message::ChangePage(Page::Home))
|
button("go back!").on_press(Message::ChangePage(Page::Home))
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue