Basic gallery support (#103)

This commit is contained in:
robrobinbin 2021-02-06 21:05:11 +01:00 committed by GitHub
parent 2a475d127a
commit cf45d53fdd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 68 additions and 4 deletions

View File

@ -72,7 +72,7 @@ async fn parse_post(json: &serde_json::Value) -> Post {
let ratio: f64 = post["data"]["upvote_ratio"].as_f64().unwrap_or(1.0) * 100.0; let ratio: f64 = post["data"]["upvote_ratio"].as_f64().unwrap_or(1.0) * 100.0;
// Determine the type of media along with the media URL // Determine the type of media along with the media URL
let (post_type, media) = media(&post["data"]).await; let (post_type, media, gallery) = media(&post["data"]).await;
// Build a post using data parsed from Reddit post API // Build a post using data parsed from Reddit post API
Post { Post {
@ -124,6 +124,7 @@ async fn parse_post(json: &serde_json::Value) -> Post {
rel_time, rel_time,
created, created,
comments: format_num(post["data"]["num_comments"].as_i64().unwrap_or_default()), comments: format_num(post["data"]["num_comments"].as_i64().unwrap_or_default()),
gallery,
} }
} }

View File

@ -46,6 +46,14 @@ pub struct Media {
pub height: i64, pub height: i64,
} }
pub struct GalleryMedia {
pub url: String,
pub width: i64,
pub height: i64,
pub caption: String,
pub outbound_url: String,
}
// Post containing content, metadata and media // Post containing content, metadata and media
pub struct Post { pub struct Post {
pub id: String, pub id: String,
@ -65,6 +73,7 @@ pub struct Post {
pub rel_time: String, pub rel_time: String,
pub created: String, pub created: String,
pub comments: String, pub comments: String,
pub gallery: Vec<GalleryMedia>,
} }
// Comment with content, post, score and data/time that it was posted // Comment with content, post, score and data/time that it was posted
@ -188,8 +197,9 @@ pub fn format_num(num: i64) -> String {
} }
} }
pub async fn media(data: &Value) -> (String, Media) { pub async fn media(data: &Value) -> (String, Media, Vec<GalleryMedia>) {
let post_type: &str; let post_type: &str;
let mut gallery = Vec::new();
// If post is a video, return the video // If post is a video, return the video
let url = if data["preview"]["reddit_video_preview"]["fallback_url"].is_string() { let url = if data["preview"]["reddit_video_preview"]["fallback_url"].is_string() {
post_type = "video"; post_type = "video";
@ -215,6 +225,25 @@ pub async fn media(data: &Value) -> (String, Media) {
} else if data["is_self"].as_bool().unwrap_or_default() { } else if data["is_self"].as_bool().unwrap_or_default() {
post_type = "self"; post_type = "self";
data["permalink"].as_str().unwrap_or_default().to_string() data["permalink"].as_str().unwrap_or_default().to_string()
} else if data["is_gallery"].as_bool().unwrap_or_default() {
post_type = "gallery";
gallery = data["gallery_data"]["items"]
.as_array()
.unwrap()
.iter()
.map(|item| {
let media_id = item["media_id"].as_str().unwrap_or_default();
let image = data["media_metadata"][media_id].as_object().unwrap();
GalleryMedia {
url: format_url(image["s"]["u"].as_str().unwrap_or_default()),
width: image["s"]["x"].as_i64().unwrap_or_default(),
height: image["s"]["y"].as_i64().unwrap_or_default(),
caption: item["caption"].as_str().unwrap_or_default().to_string(),
outbound_url: item["outbound_url"].as_str().unwrap_or_default().to_string(),
}
})
.collect::<Vec<GalleryMedia>>();
data["url"].as_str().unwrap_or_default().to_string()
} else { } else {
post_type = "link"; post_type = "link";
data["url"].as_str().unwrap_or_default().to_string() data["url"].as_str().unwrap_or_default().to_string()
@ -227,6 +256,7 @@ pub async fn media(data: &Value) -> (String, Media) {
width: data["preview"]["images"][0]["source"]["width"].as_i64().unwrap_or_default(), width: data["preview"]["images"][0]["source"]["width"].as_i64().unwrap_or_default(),
height: data["preview"]["images"][0]["source"]["height"].as_i64().unwrap_or_default(), height: data["preview"]["images"][0]["source"]["height"].as_i64().unwrap_or_default(),
}, },
gallery,
) )
} }
@ -323,7 +353,7 @@ pub async fn fetch_posts(path: &str, fallback_title: String) -> Result<(Vec<Post
let title = val(post, "title"); let title = val(post, "title");
// Determine the type of media along with the media URL // Determine the type of media along with the media URL
let (post_type, media) = media(&post["data"]).await; let (post_type, media, gallery) = media(&post["data"]).await;
posts.push(Post { posts.push(Post {
id: val(post, "id"), id: val(post, "id"),
@ -378,6 +408,7 @@ pub async fn fetch_posts(path: &str, fallback_title: String) -> Result<(Vec<Post
rel_time, rel_time,
created, created,
comments: format_num(post["data"]["num_comments"].as_i64().unwrap_or_default()), comments: format_num(post["data"]["num_comments"].as_i64().unwrap_or_default()),
gallery,
}); });
} }

View File

@ -637,7 +637,7 @@ a.search_subreddit:hover {
font-weight: bold; font-weight: bold;
} }
.post_media_image, .post .__NoScript_PlaceHolder__, .post_media_video { .post_media_image, .post .__NoScript_PlaceHolder__, .post_media_video, .gallery {
max-width: calc(100% - 40px); max-width: calc(100% - 40px);
grid-area: post_media; grid-area: post_media;
margin: 15px auto 5px auto; margin: 15px auto 5px auto;
@ -664,6 +664,24 @@ a.search_subreddit:hover {
vertical-align: bottom; vertical-align: bottom;
} }
.gallery img {
max-width: 100%;
vertical-align: bottom;
}
.gallery figcaption {
margin-top: 5px;
}
.gallery .outbound_url {
color: var(--accent);
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
display: block;
padding-top: 5px;
}
#post_url { #post_url {
color: var(--accent); color: var(--accent);
margin: 5px 20px; margin: 5px 20px;

View File

@ -78,6 +78,20 @@
</a> </a>
{% else if post.post_type == "video" || post.post_type == "gif" %} {% else if post.post_type == "video" || post.post_type == "gif" %}
<video class="post_media_video" src="{{ post.media.url }}" controls autoplay loop></video> <video class="post_media_video" src="{{ post.media.url }}" controls autoplay loop></video>
{% else if post.post_type == "gallery" %}
<div class="gallery">
{% for image in post.gallery -%}
<figure>
<a href="{{ image.url }}" ><img alt="Gallery image" src="{{ image.url }}"/></a>
<figcaption>
<p>{{ image.caption }}</p>
{% if image.outbound_url.len() > 0 %}
<p><a class="outbound_url" href="{{ image.outbound_url }}">{{ image.outbound_url }}</a>
{% endif %}
</figcaption>
</figure>
{%- endfor %}
</div>
{% else if post.post_type == "link" %} {% else if post.post_type == "link" %}
<a id="post_url" href="{{ post.media.url }}">{{ post.media.url }}</a> <a id="post_url" href="{{ post.media.url }}">{{ post.media.url }}</a>
{% endif %} {% endif %}