diff options
| author | 2026-01-10 21:29:32 +0100 | |
|---|---|---|
| committer | 2026-01-10 21:29:32 +0100 | |
| commit | 99375a7b664750c1288558f1d5c02b833a2e083c (patch) | |
| tree | 52295802e250d8dacc82bdc49740e3a2c41f5253 | |
| parent | New file xs_list_tools.h. (diff) | |
| download | snac2-99375a7b664750c1288558f1d5c02b833a2e083c.tar.gz snac2-99375a7b664750c1288558f1d5c02b833a2e083c.tar.xz snac2-99375a7b664750c1288558f1d5c02b833a2e083c.zip | |
New command-line option top_ten.
| -rw-r--r-- | Makefile | 8 | ||||
| -rw-r--r-- | Makefile.NetBSD | 8 | ||||
| -rw-r--r-- | main.c | 21 | ||||
| -rw-r--r-- | snac.h | 2 | ||||
| -rw-r--r-- | utils.c | 72 |
5 files changed, 102 insertions, 9 deletions
| @@ -46,7 +46,7 @@ update-po: | |||
| 46 | xgettext --omit-header -j -o $$a --language=C --keyword=L --from-code=utf-8 *.c ; \ | 46 | xgettext --omit-header -j -o $$a --language=C --keyword=L --from-code=utf-8 *.c ; \ |
| 47 | done | 47 | done |
| 48 | 48 | ||
| 49 | activitypub.o: activitypub.c xs.h xs_json.h xs_curl.h xs_mime.h \ | 49 | activitypub.o: activitypub.c xs.h xs_json.h xs_curl.h xs_url.h xs_mime.h \ |
| 50 | xs_openssl.h xs_regex.h xs_time.h xs_set.h xs_match.h xs_unicode.h \ | 50 | xs_openssl.h xs_regex.h xs_time.h xs_set.h xs_match.h xs_unicode.h \ |
| 51 | xs_webmention.h xs_http.h xs_http_codes.h snac.h | 51 | xs_webmention.h xs_http.h xs_http_codes.h snac.h |
| 52 | data.o: data.c xs.h xs_hex.h xs_io.h xs_json.h xs_openssl.h xs_glob.h \ | 52 | 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 \ | |||
| 68 | xs_time.h xs_glob.h xs_set.h xs_random.h xs_url.h xs_mime.h xs_match.h \ | 68 | xs_time.h xs_glob.h xs_set.h xs_random.h xs_url.h xs_mime.h xs_match.h \ |
| 69 | xs_unicode.h xs_http.h xs_http_codes.h snac.h | 69 | xs_unicode.h xs_http.h xs_http_codes.h snac.h |
| 70 | rss.o: rss.c xs.h xs_html.h xs_regex.h xs_time.h xs_match.h xs_curl.h \ | 70 | rss.o: rss.c xs.h xs_html.h xs_regex.h xs_time.h xs_match.h xs_curl.h \ |
| 71 | xs_openssl.h xs_json.h xs_http.h xs_http_codes.h snac.h | 71 | xs_openssl.h xs_json.h xs_http.h xs_http_codes.h xs_unicode.h snac.h |
| 72 | sandbox.o: sandbox.c xs.h snac.h | 72 | sandbox.o: sandbox.c xs.h snac.h |
| 73 | snac.o: snac.c xs.h xs_hex.h xs_io.h xs_unicode_tbl.h xs_unicode.h \ | 73 | snac.o: snac.c xs.h xs_hex.h xs_io.h xs_unicode_tbl.h xs_unicode.h \ |
| 74 | xs_json.h xs_curl.h xs_openssl.h xs_socket.h xs_unix_socket.h xs_url.h \ | 74 | xs_json.h xs_curl.h xs_openssl.h xs_socket.h xs_unix_socket.h xs_url.h \ |
| 75 | xs_http.h xs_http_codes.h xs_httpd.h xs_mime.h xs_regex.h xs_set.h \ | 75 | xs_http.h xs_http_codes.h xs_httpd.h xs_mime.h xs_regex.h xs_set.h \ |
| 76 | xs_time.h xs_glob.h xs_random.h xs_match.h xs_fcgi.h xs_html.h xs_po.h \ | 76 | xs_time.h xs_glob.h xs_random.h xs_match.h xs_fcgi.h xs_html.h xs_po.h \ |
| 77 | xs_webmention.h snac.h | 77 | xs_webmention.h xs_list_tools.h snac.h |
| 78 | upgrade.o: upgrade.c xs.h xs_io.h xs_json.h xs_glob.h snac.h | 78 | upgrade.o: upgrade.c xs.h xs_io.h xs_json.h xs_glob.h snac.h |
| 79 | utils.o: utils.c xs.h xs_io.h xs_json.h xs_time.h xs_openssl.h \ | 79 | utils.o: utils.c xs.h xs_io.h xs_json.h xs_time.h xs_openssl.h \ |
| 80 | xs_random.h xs_glob.h xs_curl.h xs_regex.h xs_http.h xs_http_codes.h \ | 80 | xs_random.h xs_glob.h xs_curl.h xs_regex.h xs_http.h xs_http_codes.h \ |
| 81 | snac.h | 81 | xs_list_tools.h xs_set.h snac.h |
| 82 | webfinger.o: webfinger.c xs.h xs_json.h xs_curl.h xs_mime.h xs_http.h \ | 82 | webfinger.o: webfinger.c xs.h xs_json.h xs_curl.h xs_mime.h xs_http.h \ |
| 83 | xs_http_codes.h snac.h | 83 | 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: | |||
| 35 | rm $(PREFIX_MAN)/man5/snac.5 | 35 | rm $(PREFIX_MAN)/man5/snac.5 |
| 36 | rm $(PREFIX_MAN)/man8/snac.8 | 36 | rm $(PREFIX_MAN)/man8/snac.8 |
| 37 | 37 | ||
| 38 | activitypub.o: activitypub.c xs.h xs_json.h xs_curl.h xs_mime.h \ | 38 | activitypub.o: activitypub.c xs.h xs_json.h xs_curl.h xs_url.h xs_mime.h \ |
| 39 | xs_openssl.h xs_regex.h xs_time.h xs_set.h xs_match.h xs_unicode.h \ | 39 | xs_openssl.h xs_regex.h xs_time.h xs_set.h xs_match.h xs_unicode.h \ |
| 40 | xs_webmention.h xs_http.h xs_http_codes.h snac.h | 40 | xs_webmention.h xs_http.h xs_http_codes.h snac.h |
| 41 | data.o: data.c xs.h xs_hex.h xs_io.h xs_json.h xs_openssl.h xs_glob.h \ | 41 | 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 \ | |||
| 57 | xs_time.h xs_glob.h xs_set.h xs_random.h xs_url.h xs_mime.h xs_match.h \ | 57 | xs_time.h xs_glob.h xs_set.h xs_random.h xs_url.h xs_mime.h xs_match.h \ |
| 58 | xs_unicode.h xs_http.h xs_http_codes.h snac.h | 58 | xs_unicode.h xs_http.h xs_http_codes.h snac.h |
| 59 | rss.o: rss.c xs.h xs_html.h xs_regex.h xs_time.h xs_match.h xs_curl.h \ | 59 | rss.o: rss.c xs.h xs_html.h xs_regex.h xs_time.h xs_match.h xs_curl.h \ |
| 60 | xs_openssl.h xs_json.h xs_http.h xs_http_codes.h snac.h | 60 | xs_openssl.h xs_json.h xs_http.h xs_http_codes.h xs_unicode.h snac.h |
| 61 | sandbox.o: sandbox.c xs.h snac.h | 61 | sandbox.o: sandbox.c xs.h snac.h |
| 62 | snac.o: snac.c xs.h xs_hex.h xs_io.h xs_unicode_tbl.h xs_unicode.h \ | 62 | snac.o: snac.c xs.h xs_hex.h xs_io.h xs_unicode_tbl.h xs_unicode.h \ |
| 63 | xs_json.h xs_curl.h xs_openssl.h xs_socket.h xs_unix_socket.h xs_url.h \ | 63 | xs_json.h xs_curl.h xs_openssl.h xs_socket.h xs_unix_socket.h xs_url.h \ |
| 64 | xs_http.h xs_http_codes.h xs_httpd.h xs_mime.h xs_regex.h xs_set.h \ | 64 | xs_http.h xs_http_codes.h xs_httpd.h xs_mime.h xs_regex.h xs_set.h \ |
| 65 | xs_time.h xs_glob.h xs_random.h xs_match.h xs_fcgi.h xs_html.h xs_po.h \ | 65 | xs_time.h xs_glob.h xs_random.h xs_match.h xs_fcgi.h xs_html.h xs_po.h \ |
| 66 | xs_webmention.h snac.h | 66 | xs_webmention.h xs_list_tools.h snac.h |
| 67 | upgrade.o: upgrade.c xs.h xs_io.h xs_json.h xs_glob.h snac.h | 67 | upgrade.o: upgrade.c xs.h xs_io.h xs_json.h xs_glob.h snac.h |
| 68 | utils.o: utils.c xs.h xs_io.h xs_json.h xs_time.h xs_openssl.h \ | 68 | utils.o: utils.c xs.h xs_io.h xs_json.h xs_time.h xs_openssl.h \ |
| 69 | xs_random.h xs_glob.h xs_curl.h xs_regex.h xs_http.h xs_http_codes.h \ | 69 | xs_random.h xs_glob.h xs_curl.h xs_regex.h xs_http.h xs_http_codes.h \ |
| 70 | snac.h | 70 | xs_list_tools.h xs_set.h snac.h |
| 71 | webfinger.o: webfinger.c xs.h xs_json.h xs_curl.h xs_mime.h xs_http.h \ | 71 | webfinger.o: webfinger.c xs.h xs_json.h xs_curl.h xs_mime.h xs_http.h \ |
| 72 | xs_http_codes.h snac.h | 72 | xs_http_codes.h snac.h |
| @@ -76,7 +76,8 @@ int usage(const char *cmd) | |||
| 76 | "list_create {basedir} {uid} {name} Creates a new list\n" | 76 | "list_create {basedir} {uid} {name} Creates a new list\n" |
| 77 | "list_remove {basedir} {uid} {name} Removes an existing list\n" | 77 | "list_remove {basedir} {uid} {name} Removes an existing list\n" |
| 78 | "list_add {basedir} {uid} {name} {acct} Adds an account (@user@host or actor url) to a list\n" | 78 | "list_add {basedir} {uid} {name} {acct} Adds an account (@user@host or actor url) to a list\n" |
| 79 | "list_del {basedir} {uid} {name} {actor} Deletes an actor URL from a list\n"; | 79 | "list_del {basedir} {uid} {name} {actor} Deletes an actor URL from a list\n" |
| 80 | "top_ten {basedir} {uid} [{N}] Prints the most popular posts\n"; | ||
| 80 | 81 | ||
| 81 | if (cmd == NULL) | 82 | if (cmd == NULL) |
| 82 | printf("%s", cmds); | 83 | printf("%s", cmds); |
| @@ -350,6 +351,24 @@ int main(int argc, char *argv[]) | |||
| 350 | return 0; | 351 | return 0; |
| 351 | } | 352 | } |
| 352 | 353 | ||
| 354 | if (strcmp(cmd, "top_ten") == 0) { /** **/ | ||
| 355 | int count = 10; | ||
| 356 | const char *n = GET_ARGV(); | ||
| 357 | if (xs_is_string(n)) | ||
| 358 | count = atoi(n); | ||
| 359 | |||
| 360 | xs *l = user_top_ten(&snac, count); | ||
| 361 | const xs_list *i; | ||
| 362 | |||
| 363 | xs_list_foreach(l, i) { | ||
| 364 | printf("%s %ld★ %ld↺\n", xs_list_get(i, 0), | ||
| 365 | xs_number_get_l(xs_list_get(i, 1)), | ||
| 366 | xs_number_get_l(xs_list_get(i, 2))); | ||
| 367 | } | ||
| 368 | |||
| 369 | return 0; | ||
| 370 | } | ||
| 371 | |||
| 353 | if ((url = GET_ARGV()) == NULL) | 372 | if ((url = GET_ARGV()) == NULL) |
| 354 | return usage(cmd); | 373 | return usage(cmd); |
| 355 | 374 | ||
| @@ -494,3 +494,5 @@ void rss_to_timeline(snac *user, const char *url); | |||
| 494 | void rss_poll_hashtags(void); | 494 | void rss_poll_hashtags(void); |
| 495 | 495 | ||
| 496 | void data_fsck(void); | 496 | void data_fsck(void); |
| 497 | |||
| 498 | xs_list *user_top_ten(snac *user, int count); | ||
| @@ -11,6 +11,8 @@ | |||
| 11 | #include "xs_curl.h" | 11 | #include "xs_curl.h" |
| 12 | #include "xs_regex.h" | 12 | #include "xs_regex.h" |
| 13 | #include "xs_http.h" | 13 | #include "xs_http.h" |
| 14 | #include "xs_list_tools.h" | ||
| 15 | #include "xs_set.h" | ||
| 14 | 16 | ||
| 15 | #include "snac.h" | 17 | #include "snac.h" |
| 16 | 18 | ||
| @@ -1002,6 +1004,76 @@ void import_csv(snac *user) | |||
| 1002 | snac_log(user, xs_fmt("Cannot open file %s", fn)); | 1004 | snac_log(user, xs_fmt("Cannot open file %s", fn)); |
| 1003 | } | 1005 | } |
| 1004 | 1006 | ||
| 1007 | |||
| 1008 | static int top_ten_sort(const void *v1, const void *v2) | ||
| 1009 | { | ||
| 1010 | const xs_list *l1 = *(const xs_list **)v1; | ||
| 1011 | const xs_list *l2 = *(const xs_list **)v2; | ||
| 1012 | |||
| 1013 | const char *c1 = xs_list_get(l1, 3); | ||
| 1014 | const char *c2 = xs_list_get(l2, 3); | ||
| 1015 | |||
| 1016 | return xs_cmp(c2, c1); | ||
| 1017 | } | ||
| 1018 | |||
| 1019 | |||
| 1020 | xs_list *user_top_ten(snac *user, int count) | ||
| 1021 | /* returns the top ten more popular posts by a user */ | ||
| 1022 | { | ||
| 1023 | xs *idx = xs_fmt("%s/private.idx", user->basedir); | ||
| 1024 | xs *list = index_list(idx, XS_ALL); | ||
| 1025 | xs *u_list = xs_list_new(); | ||
| 1026 | xs_set u; | ||
| 1027 | |||
| 1028 | xs_set_init(&u); | ||
| 1029 | |||
| 1030 | const char *md5; | ||
| 1031 | |||
| 1032 | xs_list_foreach(list, md5) { | ||
| 1033 | xs *obj = NULL; | ||
| 1034 | |||
| 1035 | if (!valid_status(object_get_by_md5(md5, &obj))) | ||
| 1036 | continue; | ||
| 1037 | |||
| 1038 | const char *id = xs_dict_get_def(obj, "id", "-"); | ||
| 1039 | |||
| 1040 | if (!is_msg_mine(user, id)) | ||
| 1041 | continue; | ||
| 1042 | |||
| 1043 | if (xs_set_add(&u, id) != 1) | ||
| 1044 | continue; | ||
| 1045 | |||
| 1046 | /* get metrics */ | ||
| 1047 | int ls = object_likes_len(id); | ||
| 1048 | int as = object_announces_len(id); | ||
| 1049 | |||
| 1050 | /* build the entry and convert to list */ | ||
| 1051 | xs *s = xs_fmt("%s\t%d\t%d\t%010d", id, ls, as, ls + as); | ||
| 1052 | xs *l = xs_split(s, "\t"); | ||
| 1053 | |||
| 1054 | u_list = xs_list_append(u_list, l); | ||
| 1055 | } | ||
| 1056 | |||
| 1057 | /* sort by the sum of likes and boosts */ | ||
| 1058 | xs *s_list = xs_list_sort(u_list, top_ten_sort); | ||
| 1059 | |||
| 1060 | xs_list *r = xs_list_new(); | ||
| 1061 | const xs_list *i; | ||
| 1062 | |||
| 1063 | xs_list_foreach(s_list, i) { | ||
| 1064 | r = xs_list_append(r, i); | ||
| 1065 | |||
| 1066 | if (--count <= 0) | ||
| 1067 | break; | ||
| 1068 | } | ||
| 1069 | |||
| 1070 | xs_set_free(&u); | ||
| 1071 | |||
| 1072 | return r; | ||
| 1073 | } | ||
| 1074 | |||
| 1075 | |||
| 1076 | |||
| 1005 | static const struct { | 1077 | static const struct { |
| 1006 | const char *proto; | 1078 | const char *proto; |
| 1007 | unsigned short default_port; | 1079 | unsigned short default_port; |