gui
This commit is contained in:
parent
8b414b5181
commit
340f3572d5
|
@ -7,7 +7,8 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
clap = { version = "4.3.3", features = ["derive"] }
|
||||
iced = "0.9.0"
|
||||
color-print = "0.3.5"
|
||||
iced = {version="0.10.0", features=["image", "debug", "tokio"]}
|
||||
regex = "1.8.4"
|
||||
reqwest = {version="0.11.18",features=["blocking"]}
|
||||
scraper = "0.16.0"
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
use std::{fs, path::Path, process};
|
||||
|
||||
use color_print::cprintln;
|
||||
use crate::Page;
|
||||
|
||||
pub async fn download_page_image(cache_path: &str, page: &Page) {
|
||||
let replaced = cache_path.replace('~', &crate::get_home()[..]); // replace ~ with $HOME
|
||||
crate::ensure_exists(&replaced);
|
||||
|
||||
if Path::new(&format!("{cache_path}/{}.json", page.date)).exists() {
|
||||
return;
|
||||
if Path::new(&format!("{replaced}/{}.json", page.date)).exists() {
|
||||
return
|
||||
}
|
||||
|
||||
cprintln!("<italics>downloading page image<italics>");
|
||||
let image = match reqwest::get(&page.image).await {
|
||||
Ok(image) => match image.bytes().await {
|
||||
Ok(bytes) => bytes,
|
||||
|
|
84
src/lib.rs
84
src/lib.rs
|
@ -138,7 +138,7 @@ pub struct Config {
|
|||
pub cache_folder: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct Page {
|
||||
pub date: String,
|
||||
pub next_page: Option<String>,
|
||||
|
@ -154,7 +154,7 @@ pub async fn get_page(date: &str, config: &Config) -> Page {
|
|||
))
|
||||
.exists()
|
||||
{
|
||||
match serde_json::from_str(
|
||||
match serde_json::from_str::<Page>(
|
||||
&match fs::read_to_string(
|
||||
&format!(
|
||||
"{}/{date}.json",
|
||||
|
@ -163,18 +163,20 @@ pub async fn get_page(date: &str, config: &Config) -> Page {
|
|||
) {
|
||||
Ok(var) => var,
|
||||
Err(why) => {
|
||||
eprintln!("lib::get_page: Couldn't read cache data: {why:?}");
|
||||
eprintln!("lib::get_page: Couldn't read cache data for page {date}: {why:?}");
|
||||
process::exit(1)
|
||||
}
|
||||
}[..],
|
||||
) {
|
||||
Ok(var) => var,
|
||||
Err(why) => {
|
||||
eprintln!("lib::get_page: Couldn't serialize read cache data: {why:?}");
|
||||
eprintln!(
|
||||
"lib::get_page: Couldn't serialize read cache data for page {date}: {why:?}"
|
||||
);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
let page_html = &match match reqwest::get(format!(
|
||||
"https://girlgeniusonline.com/comic.php?date={date}"
|
||||
|
@ -210,13 +212,33 @@ pub async fn get_page(date: &str, config: &Config) -> Page {
|
|||
let next = Selector::parse("#topnext").unwrap();
|
||||
let mut next_page = None;
|
||||
for element in parsed.select(&next) {
|
||||
next_page = Some(element.value().attr("href").unwrap().to_string());
|
||||
next_page = element
|
||||
.value()
|
||||
.attr("href")
|
||||
.map(|p| {
|
||||
if p.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(link_to_datestring(p.to_string()).to_string())
|
||||
}
|
||||
})
|
||||
.expect("??????????"); // i dont understand rust sometimes
|
||||
}
|
||||
|
||||
let prev = Selector::parse("#topprev").unwrap();
|
||||
let mut prev_page = None;
|
||||
for element in parsed.select(&prev) {
|
||||
prev_page = Some(element.value().attr("href").unwrap().to_string());
|
||||
prev_page = element
|
||||
.value()
|
||||
.attr("href")
|
||||
.map(|p| {
|
||||
if p.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(link_to_datestring(p.to_string()).to_string())
|
||||
}
|
||||
})
|
||||
.expect("??????????"); // if you do please yell at me as to why that expect is required
|
||||
}
|
||||
|
||||
// check if cache/date.json exists
|
||||
|
@ -228,7 +250,7 @@ pub async fn get_page(date: &str, config: &Config) -> Page {
|
|||
}
|
||||
|
||||
Page {
|
||||
date: date.to_string(),
|
||||
date: link_to_datestring(date.to_string()).to_string(),
|
||||
next_page,
|
||||
prev_page,
|
||||
image,
|
||||
|
@ -245,3 +267,47 @@ pub async fn current_page(config: &Config) -> Page {
|
|||
page
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn next_page(config: &Config) -> Option<Page> {
|
||||
let current_page = get_page(&config.latest_date[..], config).await;
|
||||
if current_page.next_page.is_some() {
|
||||
let page = get_page(
|
||||
¤t_page
|
||||
.next_page
|
||||
.expect("i shall *expect* (see what i did there) war crimes if this error pops up")
|
||||
[..],
|
||||
config,
|
||||
)
|
||||
.await;
|
||||
if page.cached {
|
||||
Some(page)
|
||||
} else {
|
||||
cache::download_page_image(&config.cache_folder[..], &page).await;
|
||||
Some(page)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn prev_page(config: &Config) -> Option<Page> {
|
||||
let current_page = get_page(&config.latest_date[..], config).await;
|
||||
if current_page.prev_page.is_some() {
|
||||
let page = get_page(
|
||||
¤t_page
|
||||
.prev_page
|
||||
.expect("i shall *expect* (see what i did there) war crimes if this error pops up")
|
||||
[..],
|
||||
config,
|
||||
)
|
||||
.await;
|
||||
if page.cached {
|
||||
Some(page)
|
||||
} else {
|
||||
cache::download_page_image(&config.cache_folder[..], &page).await;
|
||||
Some(page)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
161
src/main.rs
161
src/main.rs
|
@ -1,5 +1,9 @@
|
|||
use clap::Parser;
|
||||
use ggg::cache;
|
||||
|
||||
use ggg::{current_page, get_home, read_config};
|
||||
|
||||
use iced::widget::{button, column, container, image, row, text};
|
||||
use iced::{Application, Command, Element, Length, Theme, Settings};
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
|
@ -9,7 +13,7 @@ struct Args {
|
|||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
async fn main() -> iced::Result {
|
||||
let args = Args::parse();
|
||||
|
||||
let config_file = args.config_file;
|
||||
|
@ -20,8 +24,153 @@ async fn main() {
|
|||
ggg::ensure_exists(&config.cache_folder);
|
||||
ggg::ensure_exists(&format!("{}/images", &config.cache_folder)[..]);
|
||||
|
||||
let current_page = ggg::get_page(&config.latest_date, &config).await;
|
||||
|
||||
println!("image url: {}\ncache folder: {}", ¤t_page.image, &config.cache_folder);
|
||||
cache::download_page_image(&config.cache_folder.replace('~', &ggg::get_home()[..]), ¤t_page).await;
|
||||
Reader::run(Settings::default())
|
||||
}
|
||||
|
||||
enum Reader {
|
||||
Loading,
|
||||
Loaded { page: Book },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum Message {
|
||||
PageFound(Book),
|
||||
NextPage,
|
||||
PreviousPage,
|
||||
}
|
||||
|
||||
impl Application for Reader {
|
||||
type Message = Message;
|
||||
type Theme = Theme;
|
||||
type Executor = iced::executor::Default;
|
||||
type Flags = ();
|
||||
|
||||
fn new(_flags: ()) -> (Reader, Command<Message>) {
|
||||
(
|
||||
Reader::Loading,
|
||||
Command::perform(Book::current(), Message::PageFound),
|
||||
)
|
||||
}
|
||||
|
||||
fn title(&self) -> String {
|
||||
format!("ggg") // i didn't feel like typing out .to_string(), plus this is easier to go
|
||||
// back and change
|
||||
}
|
||||
|
||||
fn update(&mut self, message: Message) -> Command<Message> {
|
||||
match message {
|
||||
Message::NextPage => match self {
|
||||
Reader::Loading => Command::none(),
|
||||
_ => {
|
||||
*self = Reader::Loading;
|
||||
Command::perform(Book::next_page(), Message::PageFound)
|
||||
}
|
||||
},
|
||||
Message::PreviousPage => match self {
|
||||
Reader::Loading => Command::none(),
|
||||
_ => {
|
||||
*self = Reader::Loading;
|
||||
Command::perform(Book::prev_page(), Message::PageFound)
|
||||
}
|
||||
},
|
||||
Message::PageFound(page) => {
|
||||
*self = Reader::Loaded { page };
|
||||
Command::none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
let content = match self {
|
||||
Reader::Loading => column![text("Loading...").size(40),].width(Length::Shrink),
|
||||
Reader::Loaded { page } => column![
|
||||
page.view(),
|
||||
row![
|
||||
// TODO: make these disable/enable if page.next and page.prev are false
|
||||
button("Next").on_press(Message::NextPage),
|
||||
button("Prev").on_press(Message::PreviousPage),
|
||||
]
|
||||
.spacing(20)
|
||||
.align_items(iced::Alignment::Center)
|
||||
]
|
||||
.spacing(20)
|
||||
.align_items(iced::Alignment::Center),
|
||||
};
|
||||
|
||||
container(content)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.center_x()
|
||||
.center_y()
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Book {
|
||||
image: image::Handle,
|
||||
// see above todo
|
||||
next: bool,
|
||||
prev: bool,
|
||||
}
|
||||
|
||||
impl Book {
|
||||
fn view(&self) -> Element<Message> {
|
||||
row![image::viewer(self.image.clone())]
|
||||
.spacing(20)
|
||||
.align_items(iced::Alignment::Center)
|
||||
.into()
|
||||
}
|
||||
async fn current() -> Book {
|
||||
let args = Args::parse();
|
||||
let config = read_config(&args.config_file[..]);
|
||||
let page = current_page(&config).await;
|
||||
|
||||
let image = image::Handle::from_path(format!(
|
||||
"{}/images/{}.jpg",
|
||||
config.cache_folder.replace('~', &get_home()),
|
||||
ggg::link_to_datestring(page.date)
|
||||
));
|
||||
|
||||
Book {
|
||||
image,
|
||||
next: page.next_page.is_some(),
|
||||
prev: page.prev_page.is_some(),
|
||||
}
|
||||
}
|
||||
async fn next_page() -> Book {
|
||||
let args = Args::parse();
|
||||
let config = read_config(&args.config_file[..]);
|
||||
let page = ggg::next_page(&config).await.unwrap();
|
||||
|
||||
let image = image::Handle::from_path(format!(
|
||||
"{}/images/{}.jpg",
|
||||
config.cache_folder.replace('~', &get_home()),
|
||||
ggg::link_to_datestring(page.date)
|
||||
));
|
||||
|
||||
Book {
|
||||
image,
|
||||
next: page.next_page.is_some(),
|
||||
prev: page.prev_page.is_some(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn prev_page() -> Book {
|
||||
let args = Args::parse();
|
||||
let config = read_config(&args.config_file[..]);
|
||||
let page = ggg::prev_page(&config).await.unwrap();
|
||||
|
||||
let image = image::Handle::from_path(format!(
|
||||
"{}/images/{}.jpg",
|
||||
config.cache_folder.replace('~', &get_home()),
|
||||
ggg::link_to_datestring(page.date)
|
||||
));
|
||||
|
||||
Book {
|
||||
image,
|
||||
next: page.next_page.is_some(),
|
||||
prev: page.prev_page.is_some(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue