Successfully loaded a feed and items into the db, able to parse and display as markdown... kinda
This commit is contained in:
parent
7f95347330
commit
ca139525a2
7 changed files with 234 additions and 14 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
target
|
||||
Cargo.lock
|
||||
*.db
|
11
Cargo.toml
11
Cargo.toml
|
@ -8,4 +8,13 @@ iced = {git = "https://github.com/iced-rs/iced", branch = "master", features = [
|
|||
reqwest = { version = "0.12", features= ["blocking"]}
|
||||
rss = "2.0"
|
||||
web-sys = "0.3.70"
|
||||
mdka = "1.2.10"
|
||||
mdka = "1.2.10" #Not Sure if this is useful...
|
||||
rusqlite = {version="0.32",features=['bundled']}
|
||||
html2md = "0.2"
|
||||
regex = "1"
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 3
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
122
src/db.rs
Normal file
122
src/db.rs
Normal file
|
@ -0,0 +1,122 @@
|
|||
use rusqlite::{params, Connection, Result};
|
||||
use super::net::{*};
|
||||
|
||||
|
||||
/*
|
||||
Cache is the in-memory database
|
||||
Any changes/updates are written to file database
|
||||
*/
|
||||
|
||||
struct Item{
|
||||
title: String,
|
||||
content: Option<String>
|
||||
}
|
||||
|
||||
const DB_LOCATION: &str = "rsscar.db";
|
||||
|
||||
|
||||
const feeds_table_create: &str = "CREATE TABLE IF NOT EXISTS 'feeds' (
|
||||
'feedID' INTEGER NOT NULL,
|
||||
'title' TEXT NOT NULL,
|
||||
'description' TEXT,
|
||||
'icon' BLOB,
|
||||
'url' text not null unique on conflict replace,
|
||||
'subscribed' INTEGER,
|
||||
'last_updated' TEXT ,
|
||||
PRIMARY KEY('feedID')
|
||||
);";
|
||||
const feeds_index_create: &str = "CREATE INDEX IF NOT EXISTS 'subscribed_feeds_idx' ON 'feeds' (
|
||||
'feedID' ASC
|
||||
) WHERE 'subscribed' = 1;";
|
||||
const items_table_create: &str = "CREATE TABLE IF NOT EXISTS 'items' (
|
||||
'itemID' INTEGER NOT NULL,
|
||||
'title' TEXT NOT NULL,
|
||||
'icon' BLOB,
|
||||
'url' text not null unique on conflict replace,
|
||||
'description' TEXT,
|
||||
'content' TEXT,
|
||||
'read' INTEGER DEFAULT 0,
|
||||
PRIMARY KEY('itemID')
|
||||
);";
|
||||
const items_index_create: &str = "CREATE INDEX IF NOT EXISTS 'items_idx' on 'items'('itemID' ASC);";
|
||||
|
||||
pub fn initialize() {
|
||||
let conn = Connection::open(DB_LOCATION).unwrap();
|
||||
conn.execute(feeds_table_create,[]).unwrap();
|
||||
conn.execute(feeds_index_create,[]).unwrap();
|
||||
conn.execute(items_table_create,[]).unwrap();
|
||||
conn.execute(items_index_create,[]).unwrap();
|
||||
conn.close();
|
||||
println!("Database Initialized.")
|
||||
|
||||
}
|
||||
|
||||
pub fn add_feed(url: &str) {
|
||||
let conn = Connection::open(DB_LOCATION).unwrap();
|
||||
let feed = load_rss(url).unwrap();
|
||||
let new_feed = feed.clone();
|
||||
conn.execute("insert into feeds(title,url,description) values(?1,?2,?3)",
|
||||
[feed.title,url.to_owned(),feed.description]).unwrap();
|
||||
conn.close();
|
||||
store_items(new_feed);
|
||||
//defaulting to Libre Solutions
|
||||
}
|
||||
|
||||
|
||||
pub fn store_items(feed: rss::Channel) {
|
||||
let conn = Connection::open(DB_LOCATION).unwrap();
|
||||
feed.items.iter().for_each(|i: &rss::Item|{
|
||||
conn.execute("insert into items(url,title,description,content) values(?1,?2,?3,?4)",[
|
||||
i.link.clone(),
|
||||
i.title.clone(),
|
||||
i.description.clone(),
|
||||
i.content.clone()]
|
||||
).unwrap();
|
||||
});
|
||||
conn.close();
|
||||
}
|
||||
|
||||
pub fn return_item() -> String{
|
||||
let conn = Connection::open(DB_LOCATION).unwrap();
|
||||
let item = conn.query_row("select title,content from items where rowid=?1",[1],|row|{
|
||||
Ok(
|
||||
Item { title: row.get(0).unwrap(), content: row.get(1).unwrap() }
|
||||
)
|
||||
}).unwrap();
|
||||
match item.content {
|
||||
Some(content) => content,
|
||||
None => panic!()
|
||||
}
|
||||
}
|
||||
|
||||
struct ReturnedFeedURLs{
|
||||
url: String
|
||||
}
|
||||
pub fn update_feeds() {
|
||||
//get feeds
|
||||
let conn = Connection::open(DB_LOCATION).unwrap();
|
||||
let mut stmt = conn.prepare("select url from feeds").unwrap();
|
||||
let rows = stmt.query_map([],|row| {
|
||||
Ok(ReturnedFeedURLs{
|
||||
url:row.get(0).unwrap()
|
||||
})
|
||||
}).unwrap();
|
||||
let mut urls: Vec<String> = Vec::new();
|
||||
for feed in rows{
|
||||
let url = feed.unwrap().url.clone();
|
||||
urls.push(url);
|
||||
}
|
||||
stmt.finalize();
|
||||
conn.close();
|
||||
|
||||
for u in urls {
|
||||
store_items(load_rss(&u).unwrap());
|
||||
}
|
||||
|
||||
|
||||
|
||||
//for each feed
|
||||
// insert items into database
|
||||
|
||||
//close out
|
||||
}
|
17
src/html.rs
17
src/html.rs
|
@ -1,3 +1,16 @@
|
|||
pub fn process_html(content: String) -> String {
|
||||
content
|
||||
use html2md;
|
||||
use regex::Regex;
|
||||
|
||||
|
||||
/* this works, but...
|
||||
- images are omitted
|
||||
- Blockquotes don't display
|
||||
|
||||
|
||||
*/
|
||||
|
||||
pub fn process(content: String) -> String {
|
||||
let re = Regex::new(r"(?s)<iframe[^>]*>.*?</iframe>").unwrap();
|
||||
let cleaned = re.replace_all(&content,"");
|
||||
html2md::parse_html(&cleaned)
|
||||
}
|
61
src/main.rs
61
src/main.rs
|
@ -1,16 +1,68 @@
|
|||
mod net;
|
||||
use iced::{application, widget::{self, button, column, row, text}, Settings, Theme};
|
||||
use db::initialize;
|
||||
use iced::{application, widget::{self, button, column, markdown, row, text}, Settings, Theme};
|
||||
use net::load_rss;
|
||||
use rss::Channel;
|
||||
mod ui;
|
||||
mod html;
|
||||
mod db;
|
||||
|
||||
pub fn main() -> iced::Result {
|
||||
iced::application("Really Sweet Stuff",State::update,State::view)
|
||||
|
||||
|
||||
/*pub fn main() -> iced::Result {
|
||||
db::initialize();
|
||||
iced::application("Really Sweet Stuff",State::update,State::view)
|
||||
.theme(theme)
|
||||
.run()
|
||||
}*/
|
||||
pub fn main() -> iced::Result{
|
||||
db::initialize();
|
||||
db::add_feed("https://libresolutions.network/archive/index.xml");
|
||||
iced::application("Really Sweet Stuff",Viewer::update,Viewer::view)
|
||||
.run()
|
||||
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
struct Viewer {
|
||||
content: Vec<markdown::Item>
|
||||
}
|
||||
impl Default for Viewer{
|
||||
fn default() -> Self {
|
||||
Self { content: markdown::parse(&html::process(db::return_item())).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
enum Changes{
|
||||
Nullchange(markdown::Url)
|
||||
}
|
||||
|
||||
impl Viewer{
|
||||
fn update(&mut self, _mes: Changes) {
|
||||
|
||||
}
|
||||
fn view(&self) -> iced::Element<'_, Changes> {
|
||||
widget::container(
|
||||
widget::scrollable(
|
||||
markdown::view(
|
||||
&self.content,
|
||||
markdown::Settings::default(),
|
||||
markdown::Style::from_palette(iced::Theme::Dark.palette())
|
||||
).map(Changes::Nullchange))
|
||||
)
|
||||
.align_x(iced::alignment::Horizontal::Center)
|
||||
.align_y(iced::alignment::Vertical::Center)
|
||||
.width(iced::Length::Fill)
|
||||
.height(iced::Length::Fill)
|
||||
.padding(5)
|
||||
.into()
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
#[derive(Clone,Debug)]
|
||||
struct State {
|
||||
scene: Scene,
|
||||
|
@ -52,9 +104,8 @@ impl Default for State {
|
|||
fn default() -> Self {
|
||||
let main = net::load_rss("https://libresolutions.network/rss").unwrap();
|
||||
let small = net::load_rss("https://libresolutions.network/about/index.xml").unwrap();
|
||||
let test = net::load_rss("http://localhost:1313/about/index.xml").unwrap();
|
||||
let gabefeed = net::load_rss("https://gabe.rocks/rss").unwrap();
|
||||
let channels = vec![test];
|
||||
let channels = vec![small];
|
||||
Self {
|
||||
scene: Scene::ItemView,
|
||||
channels,
|
||||
|
|
23
src/net.rs
23
src/net.rs
|
@ -23,10 +23,29 @@ pub fn load_rss(url: &str) -> Option<Channel>{
|
|||
Err(e) => { panic!("Empty response")}
|
||||
}
|
||||
},
|
||||
Err(err) => {panic!("Error loading feed.")}
|
||||
Err(err) => {panic!("Error loading feed.:{}",err)}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_item_image(item: &rss::Item) -> Option<&str> {
|
||||
// Only bother with itunes:image
|
||||
print!("{} \n", item.title().unwrap());
|
||||
match item.itunes_ext() {
|
||||
Some(e) => match e.image() {
|
||||
Some(img) => {
|
||||
println!("Image found: {}", img);
|
||||
Some(img)
|
||||
}
|
||||
None => {
|
||||
println!("Itunes extension found, but image was not..");
|
||||
None
|
||||
}
|
||||
},
|
||||
None => {
|
||||
println!("found no extensions");
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn download_image(url: &str) -> Option<iced::widget::image::Handle>{
|
||||
match reqwest::blocking::get(url) {
|
||||
Ok(r) => {
|
||||
|
|
13
src/ui.rs
13
src/ui.rs
|
@ -1,7 +1,7 @@
|
|||
use std::cell::Cell;
|
||||
|
||||
use crate::net::download_image;
|
||||
|
||||
use super::html;
|
||||
use super::net;
|
||||
use iced::{
|
||||
self,
|
||||
|
@ -115,7 +115,7 @@ pub fn item_view(item: &rss::Item) -> Container<Message> {
|
|||
text(title).size(50),
|
||||
text(date).size(25),
|
||||
text(desc).size(35),
|
||||
iced::widget::scrollable(text(super::html::process_html(content)).size(25)),
|
||||
iced::widget::scrollable(text(html::process(content)).size(25)),
|
||||
]
|
||||
.spacing(10)
|
||||
.align_x(iced::Alignment::Start);
|
||||
|
@ -124,6 +124,11 @@ pub fn item_view(item: &rss::Item) -> Container<Message> {
|
|||
.height(Fill)
|
||||
}
|
||||
|
||||
//Display Story
|
||||
pub fn content_view<'a>(content: String) -> Container<'a, Message>{
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn fancy_button<'a>(
|
||||
icon: iced::widget::Image<Handle>,
|
||||
title: &'a str,
|
||||
|
@ -136,7 +141,7 @@ pub fn fancy_button<'a>(
|
|||
.align_x(iced::Alignment::Start)
|
||||
.spacing(5)
|
||||
]
|
||||
.spacing(5)
|
||||
.spacing(15)
|
||||
.align_y(iced::Alignment::Center),
|
||||
)
|
||||
.align_x(iced::alignment::Horizontal::Center);
|
||||
|
@ -145,7 +150,7 @@ pub fn fancy_button<'a>(
|
|||
.width(Fill)
|
||||
}
|
||||
|
||||
fn get_item_image(item: &rss::Item) -> Option<&str> {
|
||||
pub fn get_item_image(item: &rss::Item) -> Option<&str> {
|
||||
// Only bother with itunes:image
|
||||
print!("{} \n", item.title().unwrap());
|
||||
match item.itunes_ext() {
|
||||
|
|
Loading…
Reference in a new issue