mirror of
https://github.com/redlib-org/redlib.git
synced 2025-06-03 13:20:36 +00:00
feat(scraper): add scraper CLI
This commit is contained in:
parent
49ef59e000
commit
f3d2f0cc59
4 changed files with 114 additions and 3 deletions
73
src/scraper/main.rs
Normal file
73
src/scraper/main.rs
Normal file
|
@ -0,0 +1,73 @@
|
|||
use std::{fmt::Display, io::Write};
|
||||
|
||||
use clap::{Parser, ValueEnum};
|
||||
use redlib::utils::Post;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(name = "my_cli")]
|
||||
#[command(about = "A simple CLI example", long_about = None)]
|
||||
struct Cli {
|
||||
#[arg(short = 's', long = "sub")]
|
||||
sub: String,
|
||||
|
||||
#[arg(short = 'c', long = "count")]
|
||||
count: usize,
|
||||
|
||||
#[arg(long = "sort")]
|
||||
sort: SortOrder,
|
||||
|
||||
#[arg(short = 'f', long = "format", value_enum)]
|
||||
format: Format,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, ValueEnum)]
|
||||
enum SortOrder {
|
||||
Hot,
|
||||
Rising,
|
||||
New,
|
||||
Top,
|
||||
Controversial,
|
||||
}
|
||||
|
||||
impl Display for SortOrder {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
SortOrder::Hot => write!(f, "hot"),
|
||||
SortOrder::Rising => write!(f, "rising"),
|
||||
SortOrder::New => write!(f, "new"),
|
||||
SortOrder::Top => write!(f, "top"),
|
||||
SortOrder::Controversial => write!(f, "controversial"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, ValueEnum)]
|
||||
enum Format {
|
||||
Json,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let cli = Cli::parse();
|
||||
let (sub, final_count, sort, format) = (cli.sub, cli.count, cli.sort, cli.format);
|
||||
let initial = format!("/r/{sub}/{sort}.json?&raw_json=1");
|
||||
let (mut posts, mut after) = Post::fetch(&initial, false).await.unwrap();
|
||||
while posts.len() < final_count {
|
||||
print!("\r");
|
||||
let path = format!("/r/{sub}/{sort}.json?sort={sort}&t=&after={after}&raw_json=1");
|
||||
let (new_posts, new_after) = Post::fetch(&path, false).await.unwrap();
|
||||
posts.extend(new_posts);
|
||||
after = new_after;
|
||||
// Print number of posts fetched
|
||||
print!("Fetched {} posts", posts.len());
|
||||
std::io::stdout().flush().unwrap();
|
||||
}
|
||||
|
||||
match format {
|
||||
Format::Json => {
|
||||
let filename: String = format!("{sub}.json");
|
||||
let json = serde_json::to_string(&posts).unwrap();
|
||||
std::fs::write(filename, json).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
15
src/utils.rs
15
src/utils.rs
|
@ -11,6 +11,7 @@ use once_cell::sync::Lazy;
|
|||
use regex::Regex;
|
||||
use rinja::Template;
|
||||
use rust_embed::RustEmbed;
|
||||
use serde::Serialize;
|
||||
use serde_json::Value;
|
||||
use serde_json_path::{JsonPath, JsonPathExt};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
@ -46,6 +47,7 @@ pub enum ResourceType {
|
|||
}
|
||||
|
||||
// Post flair with content, background color and foreground color
|
||||
#[derive(Serialize)]
|
||||
pub struct Flair {
|
||||
pub flair_parts: Vec<FlairPart>,
|
||||
pub text: String,
|
||||
|
@ -54,7 +56,7 @@ pub struct Flair {
|
|||
}
|
||||
|
||||
// Part of flair, either emoji or text
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Serialize)]
|
||||
pub struct FlairPart {
|
||||
pub flair_part_type: String,
|
||||
pub value: String,
|
||||
|
@ -96,12 +98,14 @@ impl FlairPart {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct Author {
|
||||
pub name: String,
|
||||
pub flair: Flair,
|
||||
pub distinguished: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct Poll {
|
||||
pub poll_options: Vec<PollOption>,
|
||||
pub voting_end_timestamp: (String, String),
|
||||
|
@ -129,6 +133,7 @@ impl Poll {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct PollOption {
|
||||
pub id: u64,
|
||||
pub text: String,
|
||||
|
@ -158,13 +163,14 @@ impl PollOption {
|
|||
}
|
||||
|
||||
// Post flags with nsfw and stickied
|
||||
#[derive(Serialize)]
|
||||
pub struct Flags {
|
||||
pub spoiler: bool,
|
||||
pub nsfw: bool,
|
||||
pub stickied: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct Media {
|
||||
pub url: String,
|
||||
pub alt_url: String,
|
||||
|
@ -264,6 +270,7 @@ impl Media {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct GalleryMedia {
|
||||
pub url: String,
|
||||
pub width: i64,
|
||||
|
@ -304,6 +311,7 @@ impl GalleryMedia {
|
|||
}
|
||||
|
||||
// Post containing content, metadata and media
|
||||
#[derive(Serialize)]
|
||||
pub struct Post {
|
||||
pub id: String,
|
||||
pub title: String,
|
||||
|
@ -470,7 +478,7 @@ pub struct Comment {
|
|||
pub prefs: Preferences,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
#[derive(Default, Clone, Serialize)]
|
||||
pub struct Award {
|
||||
pub name: String,
|
||||
pub icon_url: String,
|
||||
|
@ -484,6 +492,7 @@ impl std::fmt::Display for Award {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct Awards(pub Vec<Award>);
|
||||
|
||||
impl std::ops::Deref for Awards {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue