extern crate clap;
extern crate serde;
extern crate tokio;
extern crate bytes;
extern crate reqwest;
extern crate serde_json;
use clap::App;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let matches = App::new("ygoprodb-extractor")
.version("1.0")
.author("whoastonic <kingstonicthe1@gmail.com>")
.about("Extract card/cardset data from YGOPro, then insert into a JSON file.")
.arg(clap::Arg::with_name("output")
.short("o")
.long("output")
.value_name("OUTPUT")
.help("Sets output file.")
.takes_value(true))
.aliases(&["ygopro"])
.get_matches();
let output = matches.value_of("output").unwrap_or("ygoprodb.json");
let ygoprodb_data = request::rcards().await?;
files::write_to_json(ygoprodb_data.as_bytes(), &output)
.expect("cannot write to JSON file.");
Ok(())
}
pub mod request {
const CARD_ENDPOINT: &'static str = "https://db.ygoprodeck.com/api/v7/cardinfo.php?misc=yes";
const SETS_ENDPOINT: &'static str = "https://db.ygoprodeck.com/api/v7/cardsets.php";
pub mod schemes {
#[derive(serde::Deserialize, serde::Serialize)]
pub struct ToJSON {
pub sets: Vec<SetsData>,
pub cards: Vec<CardData>
}
#[derive(Debug, serde::Deserialize)]
pub struct CardEndpointResponse {
pub data: Vec<CardData>
}
#[derive(serde::Deserialize, serde::Serialize)]
pub struct SetsData {
pub set_name: String,
pub set_code: String,
pub num_of_cards: usize,
pub tcg_date: Option<String>,
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct CardData {
pub id: usize,
pub name: String,
pub r#type: String,
pub desc: String,
pub race: String,
pub archetype: Option<String>,
pub card_sets: Option<Vec<CardsSet>>,
pub card_images: Vec<CardsImage>,
pub card_prices: Option<Vec<CardsPrice>>,
pub misc_info: Option<Vec<MiscInfo>>,
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct MiscInfo {
pub beta_name: Option<String>,
pub views: isize,
pub viewsweek: isize,
pub upvotes: isize,
pub downvotes: isize,
pub formats: Vec<String>,
pub tcg_date: Option<String>,
pub ocg_date: Option<String>,
pub konami_id: Option<isize>,
pub has_effect: Option<isize>,
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct CardsImage {
pub id: usize,
pub image_url: String,
pub image_url_small: String,
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct CardsPrice {
tcgplayer_price: String,
ebay_price: String,
amazon_price: String,
coolstuffinc_price: String,
cardmarket_price: String,
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct CardsSet {
pub set_name: String,
pub set_code: String,
pub set_rarity: String,
pub set_rarity_code: String,
pub set_price: String,
}
}
pub async fn rcards () -> reqwest::Result<String> {
let cards_bytes: schemes::CardEndpointResponse = reqwest::get(CARD_ENDPOINT)
.await?
.json()
.await?;
let sets_bytes: Vec<schemes::SetsData> = reqwest::get(SETS_ENDPOINT)
.await?
.json()
.await?;
let to_json = serde_json::to_string(&schemes::ToJSON {
sets: sets_bytes,
cards: cards_bytes.data,
}).expect("cannot parse to JSON");
Ok(to_json)
}
}
pub mod files {
use std::fs::{OpenOptions};
use std::io::{self, Write};
pub fn write_to_json (data: &[u8], file: &str) -> io::Result<()> {
match OpenOptions::new()
.write(true)
.create(true)
.open(file)
{
Ok(mut file) => Ok(file.write_all(data).expect("cannot write to file.")),
Err(error) => Err(error)
}
}
}