Add media support
This commit is contained in:
parent
8cb8e86de6
commit
fb1f45817c
15
models.cpp
15
models.cpp
|
@ -52,6 +52,20 @@ void from_json(const json& j, Account& account) {
|
|||
account.server = sm.str(1);
|
||||
}
|
||||
|
||||
void from_json(const json& j, Media& media) {
|
||||
j.at("type").get_to(media.type);
|
||||
j.at("url").get_to(media.url);
|
||||
if (!j.at("preview_url").is_null()) {
|
||||
media.preview_url = j["preview_url"].get<std::string>();
|
||||
}
|
||||
if (!j.at("remote_url").is_null()) {
|
||||
media.remote_url = j["remote_url"].get<std::string>();
|
||||
}
|
||||
if (!j.at("description").is_null()) {
|
||||
media.description = j["description"].get<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
void from_json(const json& j, Post& post) {
|
||||
j.at("id").get_to(post.id);
|
||||
post.created_at = parse_rfc3339(j.at("created_at").get_ref<const std::string&>());
|
||||
|
@ -77,6 +91,7 @@ void from_json(const json& j, Post& post) {
|
|||
from_json(j["reblog"].get<json>(), *post.reblog.get());
|
||||
}
|
||||
j.at("account").get_to(post.account);
|
||||
j.at("media_attachments").get_to(post.media_attachments);
|
||||
j.at("emojis").get_to(post.emojis);
|
||||
}
|
||||
|
||||
|
|
12
models.h
12
models.h
|
@ -10,7 +10,7 @@
|
|||
enum PostSortingMethod {
|
||||
Posts = 0,
|
||||
PostsAndReplies,
|
||||
Media,
|
||||
MediaOnly,
|
||||
};
|
||||
|
||||
struct Emoji {
|
||||
|
@ -50,6 +50,14 @@ struct Account {
|
|||
}
|
||||
};
|
||||
|
||||
struct Media {
|
||||
std::string type;
|
||||
std::string url;
|
||||
std::optional<std::string> preview_url;
|
||||
std::optional<std::string> remote_url;
|
||||
std::optional<std::string> description;
|
||||
};
|
||||
|
||||
struct Post {
|
||||
std::string id;
|
||||
time_t created_at;
|
||||
|
@ -64,10 +72,12 @@ struct Post {
|
|||
blankie::html::HTMLString content;
|
||||
std::unique_ptr<Post> reblog;
|
||||
Account account;
|
||||
std::vector<Media> media_attachments;
|
||||
std::vector<Emoji> emojis;
|
||||
};
|
||||
|
||||
void from_json(const nlohmann::json& j, Emoji& emoji);
|
||||
void from_json(const nlohmann::json& j, AccountField& field);
|
||||
void from_json(const nlohmann::json& j, Account& account);
|
||||
void from_json(const nlohmann::json& j, Media& media);
|
||||
void from_json(const nlohmann::json& j, Post& post);
|
||||
|
|
|
@ -28,11 +28,19 @@ html {
|
|||
font-size: var(--font-size);
|
||||
font-family: sans-serif;
|
||||
padding: 10px;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
p, details {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
details[open] {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
img {
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--accent-color);
|
||||
|
@ -76,6 +84,32 @@ a:hover {
|
|||
margin-left: auto;
|
||||
}
|
||||
|
||||
.post-attachments:not(:empty) {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
/* https://stackoverflow.com/a/7354648 */
|
||||
@media (min-width: 801px) {
|
||||
.post-attachments {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-gap: 0.5em;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.post-attachments * {
|
||||
margin: initial;
|
||||
}
|
||||
}
|
||||
.post-attachments :is(img, video, audio) {
|
||||
width: 320px;
|
||||
height: 180px;
|
||||
}
|
||||
/* do not ask why not fit-content or min-content. i spent one hour on this, and that is one hour too long to be spending on this god damn grid */
|
||||
.post-attachments audio {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
/* ERROR PAGE */
|
||||
.error {
|
||||
text-align: center;
|
||||
|
|
|
@ -62,7 +62,7 @@ void user_route(const httplib::Request& req, httplib::Response& res) {
|
|||
body.nodes.push_back(Element("p", {{"class", "user_page-more_posts"}}, {"There are no more posts"}));
|
||||
}
|
||||
|
||||
serve(req, res, account->display_name + " (" + account->acct() + ')', std::move(body));
|
||||
serve(req, res, account->display_name + " (@" + account->acct() + ')', std::move(body));
|
||||
}
|
||||
|
||||
|
||||
|
@ -112,7 +112,7 @@ static inline Element user_header(const httplib::Request& req, const std::string
|
|||
Element("nav", {{"class", "user_page-user_posts_nav"}, {"id", "user_posts_nav"}}, {
|
||||
sorting_method_link(req, server, account, sorting_method, PostSortingMethod::Posts),
|
||||
sorting_method_link(req, server, account, sorting_method, PostSortingMethod::PostsAndReplies),
|
||||
sorting_method_link(req, server, account, sorting_method, PostSortingMethod::Media),
|
||||
sorting_method_link(req, server, account, sorting_method, PostSortingMethod::MediaOnly),
|
||||
}),
|
||||
});
|
||||
return header;
|
||||
|
|
|
@ -17,6 +17,7 @@ static inline void preprocess_link(const httplib::Request& req, const std::strin
|
|||
static inline bool should_fix_link(lxb_dom_element_t* element, const std::string& cls);
|
||||
static inline lxb_dom_node_t* emojify(lxb_dom_node_t* child, const std::vector<Emoji>& emojis);
|
||||
static inline std::vector<lxb_dom_node*> emojify(lxb_dom_document_t* document, std::string str, const std::vector<Emoji>& emojis);
|
||||
static inline Element serialize_media(const Media& media);
|
||||
|
||||
class CurlUrlException : public std::exception {
|
||||
public:
|
||||
|
@ -34,7 +35,7 @@ void serve(const httplib::Request& req, httplib::Response& res, std::string titl
|
|||
using namespace std::string_literals;
|
||||
|
||||
std::string css_url = get_origin(req) + "/style.css";
|
||||
res.set_header("Content-Security-Policy", "default-src 'none'; img-src https:; media-src: https:; style-src "s + css_url);
|
||||
res.set_header("Content-Security-Policy", "default-src 'none'; img-src https:; media-src https:; style-src "s + css_url);
|
||||
|
||||
Element head("head", {
|
||||
Element("meta", {{"charset", "utf-8"}}, {}),
|
||||
|
@ -176,7 +177,14 @@ Element serialize_post(const httplib::Request& req, const std::string& server, c
|
|||
: "Created: "s + full_time(post.created_at) + "\nEdited: " + full_time(post.edited_at);
|
||||
const char* time_badge = post.edited_at < 0 ? "" : " (edited)";
|
||||
|
||||
Node contents = preprocess_html(req, server, post.emojis, post.content);
|
||||
Element contents("div", {preprocess_html(req, server, post.emojis, post.content)});
|
||||
Element post_attachments("div", {{"class", "post-attachments"}}, {});
|
||||
post_attachments.nodes.reserve(post.media_attachments.size());
|
||||
for (const Media& media : post.media_attachments) {
|
||||
post_attachments.nodes.push_back(serialize_media(media));
|
||||
}
|
||||
contents.nodes.push_back(std::move(post_attachments));
|
||||
|
||||
if (post.sensitive) {
|
||||
std::string spoiler_text = !post.spoiler_text.empty() ? post.spoiler_text : "See more";
|
||||
contents = Element("details", {
|
||||
|
@ -366,3 +374,37 @@ static inline std::vector<lxb_dom_node_t*> emojify(lxb_dom_document_t* document,
|
|||
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline Element serialize_media(const Media& media) {
|
||||
Element element = [&]() {
|
||||
if (media.type == "image") {
|
||||
return Element("a", {{"href", media.url}}, {
|
||||
Element("img", {{"src", media.preview_url.value_or(media.url)}}, {}),
|
||||
});
|
||||
} else if (media.type == "video") {
|
||||
Element video("video", {{"controls", ""}, {"src", media.url}}, {});
|
||||
if (media.preview_url) {
|
||||
video.attributes.push_back({"poster", *media.preview_url});
|
||||
}
|
||||
return video;
|
||||
} else if (media.type == "audio") {
|
||||
return Element("audio", {{"controls", ""}, {"src", media.url}}, {});
|
||||
} else if (media.type == "unknown" && media.remote_url) {
|
||||
if (media.remote_url) {
|
||||
// https://botsin.space/@lina@vt.social/111053598696451525
|
||||
return Element("a", {{"href", *media.remote_url}}, {"Media is not available from this instance, view externally"});
|
||||
} else {
|
||||
return Element("p", {"Media is not available from this instance"});
|
||||
}
|
||||
} else {
|
||||
return Element("p", {"Unsupported media type: ", media.type});
|
||||
}
|
||||
}();
|
||||
|
||||
if (media.description) {
|
||||
element.attributes.push_back({"alt", *media.description});
|
||||
element.attributes.push_back({"title", *media.description});
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue