libwebnovel 0.9.3

A Rust crate enabling users to get chapters of a webnovel, with multiple available backends.
Documentation
use std::error::Error;
use std::fs::File;
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use std::sync::LazyLock;

use libwebnovel::{Backend, Backends, Chapter};
use log::{info, LevelFilter};

static KNOWN_PHRASES_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
    Path::new(env!["CARGO_MANIFEST_DIR"])
        .join("ressources")
        .join("royalroad")
        .join("known_anti-theft_sentences.txt")
});

const URL: &str = "https://www.royalroad.com/fiction/21220/mother-of-learning/";

fn load_known_sentences() -> Vec<String> {
    let mut f = File::open(KNOWN_PHRASES_PATH.as_path()).unwrap();
    let mut contents = String::new();
    f.read_to_string(&mut contents).unwrap();
    contents
        .lines()
        .filter(|s| !s.is_empty())
        .map(|s| s.to_string())
        .collect()
}
fn save_known_sentences(sentences: &[String]) {
    let mut file = File::create(KNOWN_PHRASES_PATH.as_path()).unwrap();
    file.write_all(sentences.join("\n").as_bytes()).unwrap();
}

fn main() -> Result<(), Box<dyn Error>> {
    pretty_env_logger::formatted_timed_builder()
        .filter(None, LevelFilter::Info)
        .init();
    let backend = Backends::new(URL)?;
    let mut diffs = load_known_sentences();
    let chapters = (0..100)
        .map(|i| {
            info!("Iteration {i}");
            backend.get_chapter(1).unwrap()
        })
        .collect::<Vec<Chapter>>();
    let reference_chapter = &chapters[0];
    for chapter in &chapters[1..] {
        for diff in diff::lines(&reference_chapter.to_string(), &chapter.to_string()) {
            if let diff::Result::Right(r) = diff {
                if !r.starts_with("<p>") {
                    continue;
                }
                let text = r
                    .strip_prefix("<p>")
                    .unwrap()
                    .strip_suffix("</p>")
                    .unwrap()
                    .to_string();
                info!("found line \"{text}\"");
                diffs.push(text)
            }
        }
    }
    diffs.sort();
    diffs.dedup();
    save_known_sentences(&diffs);
    info!("Found {} unique warnings", diffs.len());
    println!(
        "const ROYALROAD_ANTI_THEFT_TEXT: &[&str] = &[\n{}\n];",
        diffs
            .iter()
            .map(|s| format!(r#"    "{}""#, s))
            .collect::<Vec<String>>()
            .join(",\n")
    );
    Ok(())
}