From 99375a7b664750c1288558f1d5c02b833a2e083c Mon Sep 17 00:00:00 2001 From: grunfink Date: Sat, 10 Jan 2026 21:29:32 +0100 Subject: New command-line option top_ten. --- Makefile | 8 +++---- Makefile.NetBSD | 8 +++---- main.c | 21 ++++++++++++++++- snac.h | 2 ++ utils.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 102 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index ffeac1a..5614388 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,7 @@ update-po: xgettext --omit-header -j -o $$a --language=C --keyword=L --from-code=utf-8 *.c ; \ done -activitypub.o: activitypub.c xs.h xs_json.h xs_curl.h xs_mime.h \ +activitypub.o: activitypub.c xs.h xs_json.h xs_curl.h xs_url.h xs_mime.h \ xs_openssl.h xs_regex.h xs_time.h xs_set.h xs_match.h xs_unicode.h \ xs_webmention.h xs_http.h xs_http_codes.h snac.h data.o: data.c xs.h xs_hex.h xs_io.h xs_json.h xs_openssl.h xs_glob.h \ @@ -68,16 +68,16 @@ mastoapi.o: mastoapi.c xs.h xs_hex.h xs_openssl.h xs_json.h xs_io.h \ xs_time.h xs_glob.h xs_set.h xs_random.h xs_url.h xs_mime.h xs_match.h \ xs_unicode.h xs_http.h xs_http_codes.h snac.h rss.o: rss.c xs.h xs_html.h xs_regex.h xs_time.h xs_match.h xs_curl.h \ - xs_openssl.h xs_json.h xs_http.h xs_http_codes.h snac.h + xs_openssl.h xs_json.h xs_http.h xs_http_codes.h xs_unicode.h snac.h sandbox.o: sandbox.c xs.h snac.h snac.o: snac.c xs.h xs_hex.h xs_io.h xs_unicode_tbl.h xs_unicode.h \ xs_json.h xs_curl.h xs_openssl.h xs_socket.h xs_unix_socket.h xs_url.h \ xs_http.h xs_http_codes.h xs_httpd.h xs_mime.h xs_regex.h xs_set.h \ xs_time.h xs_glob.h xs_random.h xs_match.h xs_fcgi.h xs_html.h xs_po.h \ - xs_webmention.h snac.h + xs_webmention.h xs_list_tools.h snac.h upgrade.o: upgrade.c xs.h xs_io.h xs_json.h xs_glob.h snac.h utils.o: utils.c xs.h xs_io.h xs_json.h xs_time.h xs_openssl.h \ xs_random.h xs_glob.h xs_curl.h xs_regex.h xs_http.h xs_http_codes.h \ - snac.h + xs_list_tools.h xs_set.h snac.h webfinger.o: webfinger.c xs.h xs_json.h xs_curl.h xs_mime.h xs_http.h \ xs_http_codes.h snac.h diff --git a/Makefile.NetBSD b/Makefile.NetBSD index b5005ee..e752910 100644 --- a/Makefile.NetBSD +++ b/Makefile.NetBSD @@ -35,7 +35,7 @@ uninstall: rm $(PREFIX_MAN)/man5/snac.5 rm $(PREFIX_MAN)/man8/snac.8 -activitypub.o: activitypub.c xs.h xs_json.h xs_curl.h xs_mime.h \ +activitypub.o: activitypub.c xs.h xs_json.h xs_curl.h xs_url.h xs_mime.h \ xs_openssl.h xs_regex.h xs_time.h xs_set.h xs_match.h xs_unicode.h \ xs_webmention.h xs_http.h xs_http_codes.h snac.h data.o: data.c xs.h xs_hex.h xs_io.h xs_json.h xs_openssl.h xs_glob.h \ @@ -57,16 +57,16 @@ mastoapi.o: mastoapi.c xs.h xs_hex.h xs_openssl.h xs_json.h xs_io.h \ xs_time.h xs_glob.h xs_set.h xs_random.h xs_url.h xs_mime.h xs_match.h \ xs_unicode.h xs_http.h xs_http_codes.h snac.h rss.o: rss.c xs.h xs_html.h xs_regex.h xs_time.h xs_match.h xs_curl.h \ - xs_openssl.h xs_json.h xs_http.h xs_http_codes.h snac.h + xs_openssl.h xs_json.h xs_http.h xs_http_codes.h xs_unicode.h snac.h sandbox.o: sandbox.c xs.h snac.h snac.o: snac.c xs.h xs_hex.h xs_io.h xs_unicode_tbl.h xs_unicode.h \ xs_json.h xs_curl.h xs_openssl.h xs_socket.h xs_unix_socket.h xs_url.h \ xs_http.h xs_http_codes.h xs_httpd.h xs_mime.h xs_regex.h xs_set.h \ xs_time.h xs_glob.h xs_random.h xs_match.h xs_fcgi.h xs_html.h xs_po.h \ - xs_webmention.h snac.h + xs_webmention.h xs_list_tools.h snac.h upgrade.o: upgrade.c xs.h xs_io.h xs_json.h xs_glob.h snac.h utils.o: utils.c xs.h xs_io.h xs_json.h xs_time.h xs_openssl.h \ xs_random.h xs_glob.h xs_curl.h xs_regex.h xs_http.h xs_http_codes.h \ - snac.h + xs_list_tools.h xs_set.h snac.h webfinger.o: webfinger.c xs.h xs_json.h xs_curl.h xs_mime.h xs_http.h \ xs_http_codes.h snac.h diff --git a/main.c b/main.c index 29a8a51..4ba9796 100644 --- a/main.c +++ b/main.c @@ -76,7 +76,8 @@ int usage(const char *cmd) "list_create {basedir} {uid} {name} Creates a new list\n" "list_remove {basedir} {uid} {name} Removes an existing list\n" "list_add {basedir} {uid} {name} {acct} Adds an account (@user@host or actor url) to a list\n" - "list_del {basedir} {uid} {name} {actor} Deletes an actor URL from a list\n"; + "list_del {basedir} {uid} {name} {actor} Deletes an actor URL from a list\n" + "top_ten {basedir} {uid} [{N}] Prints the most popular posts\n"; if (cmd == NULL) printf("%s", cmds); @@ -350,6 +351,24 @@ int main(int argc, char *argv[]) return 0; } + if (strcmp(cmd, "top_ten") == 0) { /** **/ + int count = 10; + const char *n = GET_ARGV(); + if (xs_is_string(n)) + count = atoi(n); + + xs *l = user_top_ten(&snac, count); + const xs_list *i; + + xs_list_foreach(l, i) { + printf("%s %ld★ %ld↺\n", xs_list_get(i, 0), + xs_number_get_l(xs_list_get(i, 1)), + xs_number_get_l(xs_list_get(i, 2))); + } + + return 0; + } + if ((url = GET_ARGV()) == NULL) return usage(cmd); diff --git a/snac.h b/snac.h index 2364f72..e5efc0b 100644 --- a/snac.h +++ b/snac.h @@ -494,3 +494,5 @@ void rss_to_timeline(snac *user, const char *url); void rss_poll_hashtags(void); void data_fsck(void); + +xs_list *user_top_ten(snac *user, int count); diff --git a/utils.c b/utils.c index 4bdbaaf..fd077f6 100644 --- a/utils.c +++ b/utils.c @@ -11,6 +11,8 @@ #include "xs_curl.h" #include "xs_regex.h" #include "xs_http.h" +#include "xs_list_tools.h" +#include "xs_set.h" #include "snac.h" @@ -1002,6 +1004,76 @@ void import_csv(snac *user) snac_log(user, xs_fmt("Cannot open file %s", fn)); } + +static int top_ten_sort(const void *v1, const void *v2) +{ + const xs_list *l1 = *(const xs_list **)v1; + const xs_list *l2 = *(const xs_list **)v2; + + const char *c1 = xs_list_get(l1, 3); + const char *c2 = xs_list_get(l2, 3); + + return xs_cmp(c2, c1); +} + + +xs_list *user_top_ten(snac *user, int count) +/* returns the top ten more popular posts by a user */ +{ + xs *idx = xs_fmt("%s/private.idx", user->basedir); + xs *list = index_list(idx, XS_ALL); + xs *u_list = xs_list_new(); + xs_set u; + + xs_set_init(&u); + + const char *md5; + + xs_list_foreach(list, md5) { + xs *obj = NULL; + + if (!valid_status(object_get_by_md5(md5, &obj))) + continue; + + const char *id = xs_dict_get_def(obj, "id", "-"); + + if (!is_msg_mine(user, id)) + continue; + + if (xs_set_add(&u, id) != 1) + continue; + + /* get metrics */ + int ls = object_likes_len(id); + int as = object_announces_len(id); + + /* build the entry and convert to list */ + xs *s = xs_fmt("%s\t%d\t%d\t%010d", id, ls, as, ls + as); + xs *l = xs_split(s, "\t"); + + u_list = xs_list_append(u_list, l); + } + + /* sort by the sum of likes and boosts */ + xs *s_list = xs_list_sort(u_list, top_ten_sort); + + xs_list *r = xs_list_new(); + const xs_list *i; + + xs_list_foreach(s_list, i) { + r = xs_list_append(r, i); + + if (--count <= 0) + break; + } + + xs_set_free(&u); + + return r; +} + + + static const struct { const char *proto; unsigned short default_port; -- cgit v1.2.3