Enhance back links
- Use directory listing to ensure linked entries exist. - Use a filter array for within the past year. - Read the first line summary of each entry to include in link text.
This commit is contained in:
parent
709033f5cc
commit
927a0c3257
4 changed files with 95 additions and 24 deletions
11
Cargo.lock
generated
11
Cargo.lock
generated
|
@ -1101,6 +1101,7 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"megalodon",
|
"megalodon",
|
||||||
"regex",
|
"regex",
|
||||||
|
"relativetime",
|
||||||
"rss",
|
"rss",
|
||||||
"rustyline",
|
"rustyline",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
@ -1560,6 +1561,16 @@ version = "0.8.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
|
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "relativetime"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87b093e81f7b2ee8db5253e1343a98c8334bd5e7214e507e188d2450084e1c8d"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
"humantime",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.11.27"
|
version = "0.11.27"
|
||||||
|
|
|
@ -23,6 +23,7 @@ html2md = "0.2.14"
|
||||||
log = "0.4.19"
|
log = "0.4.19"
|
||||||
megalodon = "0.13.3"
|
megalodon = "0.13.3"
|
||||||
regex = "1.9.1"
|
regex = "1.9.1"
|
||||||
|
relativetime = { version = "0.1.4", features = ["chrono"] }
|
||||||
rss = "2.0.4"
|
rss = "2.0.4"
|
||||||
rustyline = "14.0.0"
|
rustyline = "14.0.0"
|
||||||
tokio = { version = "1.28.2", features = ["default", "full"] }
|
tokio = { version = "1.28.2", features = ["default", "full"] }
|
||||||
|
|
|
@ -113,7 +113,7 @@ fn apply_block_quote<S: AsRef<str>>(depth: usize, content: S) -> String {
|
||||||
// replace separately to avoid trailing spaces when replacing empty lines with the prefix
|
// replace separately to avoid trailing spaces when replacing empty lines with the prefix
|
||||||
let content = empty.replace_all(content.as_ref(), format!("\n{}\n", prefix.trim()));
|
let content = empty.replace_all(content.as_ref(), format!("\n{}\n", prefix.trim()));
|
||||||
let content = non_empty.replace_all(&content, |c: &Captures| {
|
let content = non_empty.replace_all(&content, |c: &Captures| {
|
||||||
format!("\n{}{}", prefix, c["initial"].to_string())
|
format!("\n{}{}", prefix, &c["initial"])
|
||||||
});
|
});
|
||||||
content.to_string()
|
content.to_string()
|
||||||
}
|
}
|
||||||
|
|
105
src/main.rs
105
src/main.rs
|
@ -9,10 +9,15 @@ use megalodon::{
|
||||||
response::Response,
|
response::Response,
|
||||||
Megalodon,
|
Megalodon,
|
||||||
};
|
};
|
||||||
|
use relativetime::RelativeTime;
|
||||||
use tokio::fs::try_exists;
|
use tokio::fs::try_exists;
|
||||||
use tokio_stream::{iter, StreamExt};
|
use tokio_stream::{iter, StreamExt};
|
||||||
|
|
||||||
use std::{env, fs::File, io::prelude::*};
|
use std::{
|
||||||
|
env,
|
||||||
|
fs::{read_dir, File},
|
||||||
|
io::{prelude::*, BufReader},
|
||||||
|
};
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
format::format_status,
|
format::format_status,
|
||||||
|
@ -127,7 +132,7 @@ async fn main() -> Result<()> {
|
||||||
Ok(exists) if exists => {
|
Ok(exists) if exists => {
|
||||||
debug!("Appending {}", output);
|
debug!("Appending {}", output);
|
||||||
let mut file = File::options().append(true).open(&output)?;
|
let mut file = File::options().append(true).open(&output)?;
|
||||||
file.write("\n\n".as_bytes())?;
|
file.write_all("\n".as_bytes())?;
|
||||||
file
|
file
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -137,21 +142,18 @@ async fn main() -> Result<()> {
|
||||||
.append(true)
|
.append(true)
|
||||||
.open(&output)
|
.open(&output)
|
||||||
.with_context(|| format!("Failed to create {}", output))?;
|
.with_context(|| format!("Failed to create {}", output))?;
|
||||||
file.write(format!("# {}\n\n", day.end.format("%Y-%m-%d")).as_bytes())?;
|
file.write_all(format!("# {}\n\n", day.end.format("%Y-%m-%d")).as_bytes())?;
|
||||||
|
|
||||||
// TODO move to separate function
|
let back_links = create_back_links(&output_dir, &day.end).await?;
|
||||||
file.write(create_back_link(&day.end, "One week ago", 7).as_bytes())?;
|
debug!("Created {back_links:?}");
|
||||||
file.write(create_back_link(&day.end, "One month ago", 30).as_bytes())?;
|
file.write_all(back_links.join("\n").as_bytes())
|
||||||
file.write(create_back_link(&day.end, "Six months ago", 6 * 30).as_bytes())?;
|
.with_context(|| "Failed to write back links!")?;
|
||||||
file.write(create_back_link(&day.end, "One year ago", 365).as_bytes())?;
|
|
||||||
file.write(create_back_link(&day.end, "Two years ago", 365 * 2).as_bytes())?;
|
|
||||||
file.write(create_back_link(&day.end, "Three years ago", 365 * 3).as_bytes())?;
|
|
||||||
|
|
||||||
file.write(b"\n")?;
|
file.write_all(b"\n")?;
|
||||||
file
|
file
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
f.write_all(&reversed.join("\n\n").as_bytes())
|
f.write_all(reversed.join("\n\n").as_bytes())
|
||||||
.with_context(|| format!("Failed to write all to {}", output))?;
|
.with_context(|| format!("Failed to write all to {}", output))?;
|
||||||
println!("Appended matching posts to {}.", output);
|
println!("Appended matching posts to {}.", output);
|
||||||
} else {
|
} else {
|
||||||
|
@ -160,14 +162,71 @@ async fn main() -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_back_link(day_end: &DateTime<Local>, anchor_text: &str, ago: i64) -> String {
|
async fn create_back_links(output_dir: &str, this_day: &DateTime<Local>) -> Result<Vec<String>> {
|
||||||
let prior_date = *day_end - Duration::days(ago);
|
//file.write_all(create_back_link_old(&day.end, "One week ago", 7).as_bytes())?;
|
||||||
// TODO check if the file exists
|
//file.write_all(create_back_link_old(&day.end, "One month ago", 30).as_bytes())?;
|
||||||
format!(
|
//file.write_all(
|
||||||
"[{}](diary:{})\n",
|
// create_back_link_old(&day.end, "Six months ago", 6 * 30).as_bytes(),
|
||||||
anchor_text,
|
//)?;
|
||||||
prior_date.format("%Y-%m-%d")
|
let within_year = [
|
||||||
)
|
(*this_day - Duration::days(7))
|
||||||
|
.format("%Y-%m-%d.md")
|
||||||
|
.to_string(),
|
||||||
|
(*this_day - Duration::days(30))
|
||||||
|
.format("%Y-%m-%d.md")
|
||||||
|
.to_string(),
|
||||||
|
(*this_day - Duration::days(6 * 30))
|
||||||
|
.format("%Y-%m-%d.md")
|
||||||
|
.to_string(),
|
||||||
|
];
|
||||||
|
let mut years_past: Vec<String> = read_dir(output_dir)?
|
||||||
|
.filter_map(|d| {
|
||||||
|
d.ok().and_then(|d| {
|
||||||
|
let d = d.file_name().to_owned();
|
||||||
|
let d = d.to_string_lossy().to_string();
|
||||||
|
if within_year.contains(&d)
|
||||||
|
|| (!d.starts_with(&this_day.format("%Y-").to_string())
|
||||||
|
&& d.ends_with(&this_day.format("-%m-%d.md").to_string()))
|
||||||
|
{
|
||||||
|
Some(d)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
years_past.sort();
|
||||||
|
years_past.reverse();
|
||||||
|
debug!("Found {years_past:?}");
|
||||||
|
|
||||||
|
let years_past = years_past
|
||||||
|
.into_iter()
|
||||||
|
.map(|b| {
|
||||||
|
let f = format!("{}/{}", output_dir.trim_end_matches("/"), b);
|
||||||
|
trace!("Building link for {f}");
|
||||||
|
let mut f =
|
||||||
|
BufReader::new(File::open(&f).with_context(|| format!("Could not open {f}"))?);
|
||||||
|
let mut first = String::default();
|
||||||
|
f.read_line(&mut first)
|
||||||
|
.with_context(|| format!("Failed to read first line of {b}"))?;
|
||||||
|
trace!("Read {first}");
|
||||||
|
let day = b.to_string();
|
||||||
|
let day = day.trim_end_matches(".md");
|
||||||
|
let day: DateTime<Local> = format!("{day}T00:00:00-04:00")
|
||||||
|
.parse()
|
||||||
|
.with_context(|| format!("Could not parse {day} as date!"))?;
|
||||||
|
let first = first.trim_start_matches(&format!("# {} - ", day.format("%Y-%m-%d")));
|
||||||
|
let link = format!(
|
||||||
|
"[{} - {}](diary:{})",
|
||||||
|
(day - *this_day).to_relative(),
|
||||||
|
first.trim(),
|
||||||
|
b
|
||||||
|
);
|
||||||
|
debug!("Link {link}");
|
||||||
|
Ok(link)
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<String>>>()?;
|
||||||
|
Ok(years_past)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum NextIter {
|
enum NextIter {
|
||||||
|
@ -215,14 +274,14 @@ async fn process_page(
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(id) = page.oldest_id {
|
if let Some(id) = page.oldest_id {
|
||||||
return Ok((Some(id.clone()), None, formatted));
|
Ok((Some(id.clone()), None, formatted))
|
||||||
} else {
|
} else {
|
||||||
return Ok((None, None, formatted));
|
Ok((None, None, formatted))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only ones authored by the user, on the date requested, that aren't a reply to any other status
|
// Only ones authored by the user, on the date requested, that aren't a reply to any other status
|
||||||
fn filter_statuses<'a>(account: &Account, day: &Range, json: &'a Vec<Status>) -> Vec<&'a Status> {
|
fn filter_statuses<'a>(account: &Account, day: &Range, json: &'a [Status]) -> Vec<&'a Status> {
|
||||||
json.iter()
|
json.iter()
|
||||||
.filter(|status| {
|
.filter(|status| {
|
||||||
status.account.id == account.id
|
status.account.id == account.id
|
||||||
|
|
Loading…
Reference in a new issue