From 238b2bcd1915e97113ade72a0ca2c0dbd2b10011 Mon Sep 17 00:00:00 2001 From: "me@ow.nekobit.net" Date: Sun, 8 May 2022 03:49:32 +0000 Subject: [PATCH] Hashtag usage graphs FossilOrigin-Name: 1a355c5c2f0b9143d27d724484d7ef81c363f7209db5dd3a4677c64a42613585 --- src/account.c | 2 +- src/graphsnbars.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++ src/graphsnbars.h | 32 ++++++++++++ src/search.c | 21 +++++++- static/bar.html | 2 +- 5 files changed, 179 insertions(+), 4 deletions(-) create mode 100644 src/graphsnbars.c create mode 100644 src/graphsnbars.h diff --git a/src/account.c b/src/account.c index 7378dde..fee69a3 100644 --- a/src/account.c +++ b/src/account.c @@ -526,7 +526,7 @@ void content_account_bookmarks(struct session* ssn, mastodont_t* api, char** dat void content_account_favourites(struct session* ssn, mastodont_t* api, char** data) { - size_t status_count = 0, statuses_html_count = 0; + size_t status_count = 0, statuses_html_count = 0; struct mstdnt_status* statuses = NULL; struct mstdnt_storage storage = { 0 }; char* status_format = NULL, diff --git a/src/graphsnbars.c b/src/graphsnbars.c new file mode 100644 index 0000000..f95bed3 --- /dev/null +++ b/src/graphsnbars.c @@ -0,0 +1,126 @@ +/* + * Treebird - Lightweight frontend for Pleroma + * Copyright (C) 2022 Nekobit + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include "graphsnbars.h" +#include "easprintf.h" +#include "string_helpers.h" + +// Pages +#include "../static/bar.chtml" +#include "../static/bar_graph.chtml" + +struct hashtags_graph_args +{ + struct mstdnt_tag* tags; + size_t tags_len; + unsigned max; + time_t rel_day; + size_t days; +}; + +char* construct_bar_graph_container(char* bars, size_t* size) +{ + char* bar_graph_html; + + size_t s = easprintf(&bar_graph_html, data_bar_graph_html, bars); + + if (size) *size = s; + return bar_graph_html; +} + +char* construct_bar(float value, int* size) +{ + char* bar_html; + + size_t s = easprintf(&bar_html, data_bar_html, + value*100); + + if (size) *size = s; + return bar_html; +} + +static char* construct_hashgraph_voidwrap(void* passed, size_t index, int* res) +{ + unsigned curr_sum = 0; + struct hashtags_graph_args* args = passed; + struct mstdnt_tag* tags = args->tags; + size_t tags_len = args->tags_len; + unsigned max = args->max; + time_t rel_day = args->rel_day; + size_t days = args->days; + + for (int i = 0; i < tags_len; ++i) + { + for (int j = 0; j < tags[i].history_len; ++j) + { + if (tags[i].history[j].day == rel_day-((days-index-1)*86400)) + curr_sum += tags[i].history[j].uses; + } + } + + return construct_bar((float)curr_sum / max, res); +} + +char* construct_hashtags_graph(struct mstdnt_tag* tags, + size_t tags_len, + size_t days, + size_t* ret_size) +{ + unsigned max_sum = 0; + unsigned curr_sum = 0; + size_t max_history_len = 0; + + // Get current time at midnight for basis, copy over + time_t t = time(NULL); + struct tm* mn_ptr = gmtime(&t); + struct tm mn; + memcpy(&mn, mn_ptr, sizeof(mn)); + mn.tm_hour = 0; + mn.tm_min = 0; + mn.tm_sec = 0; + time_t rel_day = timegm(&mn); + + // Run a loop through all the hashtags, sum each set up, + // then get the largest sum + for (size_t i = 0; i < days; ++i) + { + for (size_t j = 0; j < tags_len && i < tags[j].history_len; ++j) + { + if (tags[j].history_len > max_history_len) + max_history_len = tags[j].history_len; + if (tags[j].history[i].day >= rel_day-(i*86400)) + curr_sum += tags[j].history[i].uses; + } + + if (curr_sum > max_sum) + max_sum = curr_sum; + curr_sum = 0; + } + + struct hashtags_graph_args args = { + .tags = tags, + .tags_len = tags_len, + .max = max_sum, + .rel_day = rel_day, + .days = max_history_len, + }; + + return construct_func_strings(construct_hashgraph_voidwrap, &args, max_history_len, ret_size); +} diff --git a/src/graphsnbars.h b/src/graphsnbars.h new file mode 100644 index 0000000..78cb08f --- /dev/null +++ b/src/graphsnbars.h @@ -0,0 +1,32 @@ +/* + * Treebird - Lightweight frontend for Pleroma + * Copyright (C) 2022 Nekobit + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef GRAPHS_N_BARS_H +#define GRAPHS_N_BARS_H +#include +#include +#include "session.h" + +char* construct_bar_graph_container(char* bars, size_t* size); +char* construct_bar(float value, int* size); +char* construct_hashtags_graph(struct mstdnt_tag* tags, + size_t tags_len, + size_t days, + size_t* ret_size); + +#endif /* GRAPHS_N_BARS_H */ diff --git a/src/search.c b/src/search.c index d5ddf1b..66bfa56 100644 --- a/src/search.c +++ b/src/search.c @@ -26,6 +26,7 @@ #include "hashtag.h" #include "error.h" #include "account.h" +#include "graphsnbars.h" // Pages #include "../static/search.chtml" @@ -139,6 +140,9 @@ void content_search_accounts(struct session* ssn, mastodont_t* api, char** data) void content_search_hashtags(struct session* ssn, mastodont_t* api, char** data) { char* tags_html; + char* tags_graph = NULL; + char* tags_bars = NULL; + char* tags_page; struct mstdnt_storage storage = { 0 }; struct mstdnt_search_args args = { .account_id = NULL, @@ -163,12 +167,25 @@ void content_search_hashtags(struct session* ssn, mastodont_t* api, char** data) tags_html = construct_hashtags(results.tags, results.tags_len, NULL); if (!tags_html) tags_html = construct_error("No hashtags", E_ERROR, 1, NULL); + + tags_bars = construct_hashtags_graph(results.tags, + results.tags_len, + 14, + NULL); + tags_graph = construct_bar_graph_container(tags_bars, NULL); + if (tags_bars) free(tags_bars); } else tags_html = construct_error("An error occured.", E_ERROR, 1, NULL); + + easprintf(&tags_page, "%s%s", STR_NULL_EMPTY(tags_graph), tags_html); - search_page(ssn, api, SEARCH_HASHTAGS, STR_NULL_EMPTY(tags_html)); + search_page(ssn, api, SEARCH_HASHTAGS, tags_page); if (tags_html) free(tags_html); - // TODO cleanup shit + mastodont_storage_cleanup(&storage); + if (tags_graph) free(tags_graph); + free(tags_page); + + // TODO Cleanup shit } diff --git a/static/bar.html b/static/bar.html index 4159c47..2558771 100644 --- a/static/bar.html +++ b/static/bar.html @@ -1,3 +1,3 @@
-
+