NSFW Support

This commit is contained in:
spikecodes 2020-12-22 18:29:43 -08:00
parent 3516404a5f
commit 0957f2e339
7 changed files with 36 additions and 22 deletions

View File

@ -28,7 +28,7 @@ async fn render(id: String, sort: Option<String>, comment_id: Option<String>) ->
// Build the Reddit JSON API url
let url: String = match comment_id {
None => format!("{}.json?sort={}", id, sorting),
Some(val) => format!("{}.json?sort={}&comment={}", id, sorting, val)
Some(val) => format!("{}.json?sort={}&comment={}", id, sorting, val),
};
// Send a request to the url, receive JSON in response
@ -111,13 +111,18 @@ async fn markdown_to_html(md: &str) -> String {
// POSTS
async fn parse_post(json: serde_json::Value) -> Result<Post, &'static str> {
// Retrieve post (as opposed to comments) from JSON
let post_data: &serde_json::Value = &json["data"]["children"][0];
// Grab UTC time as unix timestamp
let unix_time: i64 = post_data["data"]["created_utc"].as_f64().unwrap().round() as i64;
// Parse post score
let score = post_data["data"]["score"].as_i64().unwrap();
// Determine the type of media along with the media URL
let media = media(&post_data["data"]).await;
// Build a post using data parsed from Reddit post API
let post = Post {
title: val(post_data, "title").await,
community: val(post_data, "subreddit").await,
@ -131,8 +136,6 @@ async fn parse_post(json: serde_json::Value) -> Result<Post, &'static str> {
url: val(post_data, "permalink").await,
score: format_num(score),
post_type: media.0,
media: media.1,
time: Utc.timestamp(unix_time, 0).format("%b %e %Y %H:%M UTC").to_string(),
flair: Flair(
val(post_data, "link_flair_text").await,
val(post_data, "link_flair_background_color").await,
@ -142,6 +145,9 @@ async fn parse_post(json: serde_json::Value) -> Result<Post, &'static str> {
"white".to_string()
},
),
nsfw: post_data["data"]["over_18"].as_bool().unwrap_or(false),
media: media.1,
time: Utc.timestamp(unix_time, 0).format("%b %e %Y %H:%M UTC").to_string(),
};
Ok(post)
@ -156,7 +162,7 @@ async fn parse_comments(json: serde_json::Value) -> Result<Vec<Comment>, &'stati
let mut comments: Vec<Comment> = Vec::new();
// For each comment, retrieve the values to build a Comment object
for comment in comment_data.iter() {
for comment in comment_data {
let unix_time: i64 = comment["data"]["created_utc"].as_f64().unwrap_or(0.0).round() as i64;
if unix_time == 0 {
continue;

View File

@ -11,11 +11,9 @@ use base64::encode;
//
// STRUCTS
//
#[allow(dead_code)]
// Post flair with text, background color and foreground color
pub struct Flair(pub String, pub String, pub String);
#[allow(dead_code)]
// Post containing content, metadata and media
pub struct Post {
pub title: String,
@ -26,12 +24,12 @@ pub struct Post {
pub url: String,
pub score: String,
pub post_type: String,
pub flair: Flair,
pub nsfw: bool,
pub media: String,
pub time: String,
pub flair: Flair,
}
#[allow(dead_code)]
// Comment with content, post, score and data/time that it was posted
pub struct Comment {
pub id: String,
@ -43,7 +41,6 @@ pub struct Comment {
pub replies: Vec<Comment>,
}
#[allow(dead_code)]
// User struct containing metadata about user
pub struct User {
pub name: String,
@ -53,7 +50,6 @@ pub struct User {
pub description: String,
}
#[allow(dead_code)]
// Subreddit struct containing metadata about community
pub struct Subreddit {
pub name: String,
@ -105,19 +101,16 @@ pub fn format_num(num: i64) -> String {
// JSON PARSING
//
#[allow(dead_code)]
// val() function used to parse JSON from Reddit APIs
pub async fn val(j: &serde_json::Value, k: &str) -> String {
String::from(j["data"][k].as_str().unwrap_or(""))
}
#[allow(dead_code)]
// nested_val() function used to parse JSON from Reddit APIs
pub async fn nested_val(j: &serde_json::Value, n: &str, k: &str) -> String {
String::from(j["data"][n][k].as_str().unwrap())
}
#[allow(dead_code)]
pub async fn fetch_posts(url: String, fallback_title: String) -> Result<(Vec<Post>, String), &'static str> {
// Send a request to the url, receive JSON in response
let req = request(url).await;
@ -135,7 +128,7 @@ pub async fn fetch_posts(url: String, fallback_title: String) -> Result<(Vec<Pos
let mut posts: Vec<Post> = Vec::new();
for post in post_list.iter() {
for post in post_list {
let img = if val(post, "thumbnail").await.starts_with("https:/") {
format_url(val(post, "thumbnail").await.as_str()).await
} else {
@ -158,8 +151,6 @@ pub async fn fetch_posts(url: String, fallback_title: String) -> Result<(Vec<Pos
score: format_num(score),
post_type: "link".to_string(),
media: img,
url: val(post, "permalink").await,
time: Utc.timestamp(unix_time, 0).format("%b %e '%y").to_string(),
flair: Flair(
val(post, "link_flair_text").await,
val(post, "link_flair_background_color").await,
@ -169,6 +160,9 @@ pub async fn fetch_posts(url: String, fallback_title: String) -> Result<(Vec<Pos
"white".to_string()
},
),
nsfw: post["data"]["over_18"].as_bool().unwrap_or(false),
url: val(post, "permalink").await,
time: Utc.timestamp(unix_time, 0).format("%b %e '%y").to_string(),
});
}
@ -180,7 +174,6 @@ pub async fn fetch_posts(url: String, fallback_title: String) -> Result<(Vec<Pos
//
// Make a request to a Reddit API and parse the JSON response
#[allow(dead_code)]
pub async fn request(mut url: String) -> Result<serde_json::Value, &'static str> {
url = format!("https://www.reddit.com/{}", url);

View File

@ -48,6 +48,7 @@ main {
footer {
display: flex;
justify-content: center;
margin-bottom: 20px;
}
button {
@ -199,6 +200,21 @@ a:not(.post_right):hover {
padding: 5px;
}
.post_score {
margin-top: 20px;
color: var(--accent);
}
.nsfw {
color: #FF5C5D;
margin-top: 20px;
border: 1px solid #FF5C5D;
padding: 5px;
font-size: 12px;
border-radius: 5px;
font-weight: bold;
}
.post_subreddit {
font-weight: bold;
}
@ -207,11 +223,6 @@ a:not(.post_right):hover {
font-size: 18px;
}
.post_score {
margin-top: 20px;
color: var(--accent);
}
.post_right {
padding: 20px 25px;
flex-grow: 1;

View File

@ -12,6 +12,7 @@
<div class="post">
<div class="post_left">
<h3 class="post_score">{{ post.score }}</h3>
{% if post.nsfw %}<div class="nsfw">NSFW</div>{% endif %}
</div>
<div class="post_right">
<h4>

View File

@ -27,6 +27,7 @@
<div class="post highlighted">
<div class="post_left">
<h3 class="post_score">{{ post.score }}</h3>
{% if post.nsfw %}<div class="nsfw">NSFW</div>{% endif %}
</div>
<div class="post_right">
<h4>

View File

@ -31,6 +31,7 @@
<div class="post">
<div class="post_left">
<h3 class="post_score">{{ post.score }}</h3>
{% if post.nsfw %}<div class="nsfw">NSFW</div>{% endif %}
</div>
<div class="post_right">
<h4>

View File

@ -25,6 +25,7 @@
<div class='post'>
<div class="post_left">
<h3 class="post_score">{{ post.score }}</h3>
{% if post.nsfw %}<div class="nsfw">NSFW</div>{% endif %}
</div>
<div class="post_right">
<h4>