master
Drake 1 year ago
parent 349f24b76f
commit b3cf350d3f

@ -0,0 +1,3 @@
[target.x86_64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=/usr/bin/mold"]

5
Cargo.lock generated

@ -1923,6 +1923,7 @@ dependencies = [
"maud",
"regex",
"serde",
"serde_json",
"tokio",
"tracing",
"tracing-subscriber",
@ -2019,9 +2020,9 @@ checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
[[package]]
name = "wattpad"
version = "0.2.4"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9826298a0db9284b994af09fef8a564840af0e9e2621440aef46a5bd066481ed"
checksum = "3d03f3af6f6244f85e6dd6a3981677de18daf8b8e1d8fd1d35642d47fc2a4e3f"
dependencies = [
"anyhow",
"regex",

@ -7,7 +7,7 @@ edition = "2021"
[dependencies]
anyhow = "1.0.69"
axum = { version = "0.6.10", features = ["macros"] }
axum = { version = "0.6.10", features = ["macros", "json"] }
cached = "0.42.0"
chrono = "0.4.24"
grass = { version = "0.12.3", features = ["macro"] }
@ -15,7 +15,8 @@ lazy_static = "1.4.0"
maud = { git = "https://github.com/lambda-fairy/maud", features = ["axum"] }
regex = "1.7.1"
serde = { version = "1.0.152", features = ["derive"] }
serde_json = "1.0.94"
tokio = { version = "1.26.0", features = ["full"] }
tracing = "0.1.37"
tracing-subscriber = "0.3.16"
wattpad = "0.2.4"
wattpad = "0.2.5"

@ -83,6 +83,7 @@ a:hover {
.story-details {
display: flex;
flex-direction: column;
align-self: flex-start;
}
}

@ -0,0 +1,53 @@
const oldOnloadHandler = window.onload ?? (() => {});
async function historyLoad() {
const historyDiv = document.getElementById("story-list");
historyDiv.textContent = "";
const readingHistory = JSON.parse(
localStorage.getItem("readingHistory") ?? "[]"
);
for (let i = 0; i < readingHistory.length; i++) {
const story = await (
await fetch(`/api/getStory?id=${readingHistory[i]}`)
).json();
const searchEle = document.createElement("a");
searchEle.className = "story";
searchEle.href =
"/story?id=" +
story.id +
(localStorage.getItem(`${story.id}_progress`)
? `&chapter=${localStorage.getItem(`${story.id}_progress`)}`
: "");
const coverEle = document.createElement("img");
coverEle.src = story.cover;
const div = document.createElement("div");
const titleEle = document.createElement("h3");
titleEle.textContent = story.title;
div.appendChild(titleEle);
const descEle = document.createElement("p");
descEle.innerHTML = story.description.replace("\n", "<br/>");
div.appendChild(descEle);
searchEle.appendChild(coverEle);
searchEle.appendChild(div);
historyDiv?.appendChild(searchEle);
}
}
window.onload = async () => {
oldOnloadHandler();
// render history
await historyLoad();
/* // clear history button
const button = document.getElementById("clear-button");
button.onclick = async () => {
localStorage.removeItem("readingHistory");
// rerender history
await historyLoad();
}; */
};

@ -18,7 +18,7 @@ pub async fn get_story(id: &str) -> Result<Story> {
.get(id)
{
let time_diff = current_time.signed_duration_since(cache_item.1);
if time_diff.num_minutes() <= 5 {
if time_diff.num_minutes() <= 15 {
tracing::debug!("Cache hit for story {}", id);
return Ok(cache_item.0.clone());
}

@ -1,8 +1,9 @@
mod cached_wattpad;
mod components;
mod routes;
mod web_api;
use routes::{index, not_found, story};
use routes::{history, index, not_found, story};
use axum::{extract::Extension, routing::get, Router};
use lazy_static::lazy_static;
@ -10,6 +11,7 @@ use maud::{html, Markup};
use std::{net::SocketAddr, sync::Arc};
use tokio::runtime::Runtime;
use wattpad::Wattpad;
use web_api::get_story;
lazy_static! {
pub static ref TOKIO: Runtime = Runtime::new().unwrap();
@ -25,6 +27,8 @@ fn main() {
let app = Router::new()
.route("/", get(index::render))
.route("/story", get(story::render))
.route("/history", get(history::render))
.route("/api/getStory", get(get_story))
.fallback(not_found::render);
tracing::info!("Listening on {}", addr);

@ -0,0 +1,60 @@
use std::sync::Arc;
use crate::cached_wattpad::*;
use crate::components::header::{Header, HeaderLink};
use crate::WATTPAD;
use axum::extract::{Extension, Query, State as AxumState};
use maud::{html, Markup, PreEscaped, DOCTYPE};
use regex::Regex;
use serde::Deserialize;
pub async fn render() -> Markup {
html! {
(DOCTYPE)
title {"Home | Voltpad"};
meta name="viewport" content="width=device-width, initial-scale=1.0";
style {(PreEscaped(
grass::include!("./css/index.scss")
))}
script {(PreEscaped(
include_str!("../../scripts/History.js")
))}
(
Header(vec![
HeaderLink {
name: "Home".to_string(),
path: "/".to_string(),
prefix: None,
postfix: None
},
HeaderLink {
name: "Search".to_string(),
path: "/search".to_string(),
prefix: None,
postfix: None
},
HeaderLink {
name: "History".to_string(),
path: "/history".to_string(),
prefix: None,
postfix: None
},
HeaderLink {
name: "About".to_string(),
path: "/about".to_string(),
prefix: None,
postfix: None
},
], "/history".to_string())
)
div .index-content {
h1 { "History" }
noscript {
h3 {
"This won't work without JS. Run off now, GNU LibreJS looking motherfuckers."
}
}
div .story-list #story-list;
}
}
}

@ -1,10 +1,12 @@
use crate::components::header::{Header, HeaderLink};
use cached::proc_macro::cached;
use maud::{html, Markup, PreEscaped};
use maud::{html, Markup, PreEscaped, DOCTYPE};
#[cached]
pub async fn render() -> Markup {
html! {
(DOCTYPE)
title {"Home | Voltpad"};
meta name="viewport" content="width=device-width, initial-scale=1.0";
style {(PreEscaped(
grass::include!("./css/index.scss")

@ -1,3 +1,4 @@
pub mod history;
pub mod index;
pub mod not_found;
pub mod story;

@ -8,6 +8,7 @@ pub async fn render() -> (StatusCode, Markup) {
(
StatusCode::NOT_FOUND,
html! {
title {"404 | Voltpad"};
meta name="viewport" content="width=device-width, initial-scale=1.0";
style {(PreEscaped(
grass::include!("./css/index.scss")

@ -27,6 +27,7 @@ pub async fn render(Query(params): Query<StoryParams>) -> Markup {
(DOCTYPE)
html {
head {
title {(format!("{} | Voltpad", part.title))};
meta name="viewport" content="width=device-width, initial-scale=1.0";
style {(PreEscaped(
grass::include!("./css/index.scss")
@ -76,6 +77,7 @@ pub async fn render(Query(params): Query<StoryParams>) -> Markup {
(DOCTYPE)
html {
head {
title {(format!("{} | Voltpad", story.title))};
meta name="viewport" content="width=device-width, initial-scale=1.0";
style {(PreEscaped(
grass::include!("./css/index.scss")

@ -0,0 +1,17 @@
use crate::cached_wattpad::get_story as get_story_from_wattpad;
use axum::extract::{Json, Query};
use serde::Deserialize;
use wattpad::Story;
#[derive(Deserialize)]
pub struct GetStoryParams {
pub id: String,
}
pub async fn get_story(Query(params): Query<GetStoryParams>) -> Json<Story> {
let story = get_story_from_wattpad(&params.id)
.await
.expect("idk jump off a bridge");
Json(story)
}
Loading…
Cancel
Save