mirror of
https://github.com/JockeTF/fimfareader.git
synced 2024-11-27 07:28:00 +01:00
Add story module for deserializing meta
This commit is contained in:
parent
2207a6150a
commit
6e01dbea9f
4 changed files with 433 additions and 0 deletions
174
Cargo.lock
generated
174
Cargo.lock
generated
|
@ -1,6 +1,180 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fimfareader"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.4.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.6.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.97"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.97"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.15.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b"
|
||||
"checksum chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "77d81f58b7301084de3b958691458a53c3f7e0b1d702f77e550b6a88e3a88abe"
|
||||
"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
|
||||
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
|
||||
"checksum libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb"
|
||||
"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
|
||||
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
|
||||
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
|
||||
"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
|
||||
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
|
||||
"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997"
|
||||
"checksum serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)" = "d46b3dfedb19360a74316866cef04687cd4d6a70df8e6a506c63512790769b72"
|
||||
"checksum serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)" = "c22a0820adfe2f257b098714323563dd06426502abbbce4f51b72ef544c5027f"
|
||||
"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704"
|
||||
"checksum syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)" = "bc945221ccf4a7e8c31222b9d1fc77aefdd6638eb901a6ce457a3dc29d4c31e8"
|
||||
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
|
||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
|
14
Cargo.toml
14
Cargo.toml
|
@ -6,3 +6,17 @@ edition = "2018"
|
|||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
||||
[dependencies.chrono]
|
||||
version = "*"
|
||||
features = ["serde"]
|
||||
|
||||
[dependencies.hex]
|
||||
version = "*"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "*"
|
||||
features = ["derive"]
|
||||
|
||||
[dependencies.serde_json]
|
||||
version = "*"
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
//! Main module.
|
||||
|
||||
pub mod story;
|
||||
|
||||
fn main() {
|
||||
println!("Hellopaca, World!");
|
||||
}
|
||||
|
|
243
src/story.rs
Normal file
243
src/story.rs
Normal file
|
@ -0,0 +1,243 @@
|
|||
//! Story meta.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use chrono::prelude::*;
|
||||
use serde::de::Error;
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use serde_json::Value;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct Story {
|
||||
pub archive: Archive,
|
||||
pub author: Author,
|
||||
pub chapters: Vec<Chapter>,
|
||||
pub color: Option<Color>,
|
||||
pub completion_status: CompletionStatus,
|
||||
pub content_rating: ContentRating,
|
||||
pub cover_image: Option<CoverImage>,
|
||||
pub date_modified: Option<DateTime<Utc>>,
|
||||
pub date_published: Option<DateTime<Utc>>,
|
||||
pub date_updated: Option<DateTime<Utc>>,
|
||||
#[serde(deserialize_with = "null_to_html")]
|
||||
pub description_html: String,
|
||||
pub id: i64,
|
||||
pub num_chapters: i32,
|
||||
pub num_comments: i32,
|
||||
pub num_dislikes: i32,
|
||||
pub num_likes: i32,
|
||||
pub num_views: i32,
|
||||
pub num_words: i32,
|
||||
pub prequel: Option<i64>,
|
||||
pub published: bool,
|
||||
pub rating: i32,
|
||||
#[serde(deserialize_with = "null_to_text")]
|
||||
pub short_description: String,
|
||||
pub status: Status,
|
||||
pub submitted: bool,
|
||||
pub tags: Vec<Tag>,
|
||||
#[serde(deserialize_with = "null_to_text")]
|
||||
pub title: String,
|
||||
pub total_num_views: i32,
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct Archive {
|
||||
pub date_checked: Option<DateTime<Utc>>,
|
||||
pub date_created: Option<DateTime<Utc>>,
|
||||
pub date_fetched: Option<DateTime<Utc>>,
|
||||
pub date_updated: Option<DateTime<Utc>>,
|
||||
pub path: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct Author {
|
||||
pub avatar: Option<BTreeMap<String, String>>,
|
||||
pub bio_html: Option<String>,
|
||||
pub date_joined: Option<DateTime<Utc>>,
|
||||
#[serde(deserialize_with = "string_to_id")]
|
||||
pub id: i64,
|
||||
pub name: String,
|
||||
pub num_blog_posts: Option<i32>,
|
||||
pub num_followers: Option<i32>,
|
||||
pub num_stories: Option<i32>,
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct Chapter {
|
||||
pub chapter_number: i32,
|
||||
pub date_modified: Option<DateTime<Utc>>,
|
||||
pub date_published: Option<DateTime<Utc>>,
|
||||
pub id: i64,
|
||||
pub num_views: i32,
|
||||
pub num_words: i32,
|
||||
pub published: bool,
|
||||
#[serde(deserialize_with = "null_to_text")]
|
||||
pub title: String,
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Color {
|
||||
red: u8,
|
||||
green: u8,
|
||||
blue: u8,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum CompletionStatus {
|
||||
Cancelled,
|
||||
Complete,
|
||||
Hiatus,
|
||||
Incomplete,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ContentRating {
|
||||
Everyone,
|
||||
Mature,
|
||||
Teen,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct CoverImage {
|
||||
pub full: String,
|
||||
pub large: String,
|
||||
pub medium: String,
|
||||
pub thumbnail: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Status {
|
||||
ApproveQueue,
|
||||
NotVisible,
|
||||
PostQueue,
|
||||
Visible,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct Tag {
|
||||
pub id: i64,
|
||||
pub name: String,
|
||||
pub old_id: String,
|
||||
pub r#type: String,
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
pub fn null_to_html<'de, D>(d: D) -> Result<String, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
match Option::deserialize(d)? {
|
||||
Some(text) => Ok(text),
|
||||
None => Ok(String::from("<p></p>")),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn null_to_text<'de, D>(d: D) -> Result<String, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
match Option::deserialize(d)? {
|
||||
Some(text) => Ok(text),
|
||||
None => Ok(String::from("")),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn string_to_id<'de, D>(d: D) -> Result<i64, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let value = Value::deserialize(d)?;
|
||||
|
||||
if value.is_i64() {
|
||||
Ok(value.as_i64().unwrap())
|
||||
} else if value.is_string() {
|
||||
value.as_str().unwrap().parse().map_err(|e| match e {
|
||||
_ => Error::custom("Could not parse ID string."),
|
||||
})
|
||||
} else {
|
||||
Err(Error::custom("Invalid type for ID value."))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Color {
|
||||
fn deserialize<D>(d: D) -> Result<Color, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let object = Value::deserialize(d)?;
|
||||
|
||||
let text = object["hex"]
|
||||
.as_str()
|
||||
.ok_or(Error::custom("Color is missing hex value."))?;
|
||||
|
||||
let array = hex::decode(text).map_err(|e| match e {
|
||||
_ => Error::custom("Color hex has invalid value."),
|
||||
})?;
|
||||
|
||||
match array[..] {
|
||||
[red, green, blue] => Ok(Color { red, green, blue }),
|
||||
_ => Err(Error::custom("Color hex has invalid length.")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CompletionStatus {
|
||||
const FIELDS: &'static [&'static str] = &["cancelled", "complete", "hiatus", "incomplete"];
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for CompletionStatus {
|
||||
fn deserialize<D>(d: D) -> Result<CompletionStatus, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
match String::deserialize(d)?.as_ref() {
|
||||
"cancelled" => Ok(CompletionStatus::Cancelled),
|
||||
"complete" => Ok(CompletionStatus::Complete),
|
||||
"hiatus" | "on hiatus" => Ok(CompletionStatus::Hiatus),
|
||||
"incomplete" => Ok(CompletionStatus::Incomplete),
|
||||
value => Err(Error::unknown_field(value, Self::FIELDS)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ContentRating {
|
||||
const FIELDS: &'static [&'static str] = &["everyone", "mature", "teen"];
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for ContentRating {
|
||||
fn deserialize<D>(d: D) -> Result<ContentRating, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
match String::deserialize(d)?.as_ref() {
|
||||
"everyone" => Ok(ContentRating::Everyone),
|
||||
"mature" => Ok(ContentRating::Mature),
|
||||
"teen" => Ok(ContentRating::Teen),
|
||||
value => Err(Error::unknown_field(value, Self::FIELDS)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Status {
|
||||
const FIELDS: &'static [&'static str] =
|
||||
&["approve_queue", "not_visible", "post_queue", "visible"];
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Status {
|
||||
fn deserialize<D>(d: D) -> Result<Status, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
match String::deserialize(d)?.as_ref() {
|
||||
"approve_queue" => Ok(Status::ApproveQueue),
|
||||
"not_visible" => Ok(Status::NotVisible),
|
||||
"post_queue" => Ok(Status::PostQueue),
|
||||
"visible" => Ok(Status::Visible),
|
||||
value => Err(Error::unknown_field(value, Self::FIELDS)),
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue