Check-in by ben on 2024-10-05 22:44:03 Improve the display of user lists. Show item creator, title, etc rather than the bare item id. Paginate list items. Add "back link" to account that owns the list. INSERTED DELETED 119 13 src/list/index.dcgi.m4 1 10 src/search/index.dcgi.m4 10 0 src/util.awk 130 23 TOTAL over 3 changed files Index: src/list/index.dcgi.m4 ================================================================== --- src/list/index.dcgi.m4 +++ src/list/index.dcgi.m4 @@ -8,14 +8,27 @@ include(src/config.awk) incl(src/api.awk) incl(src/cgi.awk) incl(src/util.awk) -function main( acct, cmd, count, iaout, id, is_private, item_id, - label, list_id, name, parts, url) +function main( acct, client_url, cmd, count, creator, iaout, id, + is_private, items, label, list_id, name, name_slug, numfound, + page, pages, rows, query, title, type, url) { - count = split(search, parts, "/") + rows = 15 + page = 1 + + # parse out page number + for (i in parts) { + if (parts[i] ~ /^rows[0-9][0-9]*$/) { + rows = substr(parts[i], 5) + } else if (parts[i] ~ /^page[0-9][0-9]*$/) { + page = substr(parts[i], 5) + } + } + + split(search, parts, "/") acct = parts[1] list_id = parts[2] print acct "'s Lists" print "" @@ -23,39 +36,131 @@ iaout = gettemp() url = api_ssl_endpoint "/services/users/" acct "/lists/" list_id api_request(url, "GET", iaout) - # format list as a gopher directory (menu) + # fetch identifiers of list members + cmd = sprintf("%s <%s 2>&1", cmd_json2tsv, iaout) FS = "\t" - name = "" - id = 0 + id = "" is_private = 0 - item_id = "" + name = "" + numfound = 0 + query = "" while ((cmd | getline) > 0) { if ($1 == ".value.list_name" && $2 == "s") { name = $3 - print "# List: " name - id = 0 is_private = 0 } else if ($1 == ".value.is_private" && $2 == "b") { if ($3 == "true") { is_private = 1 } } else if ($1 == ".value.members[].identifier" && $2 == "s") { if (!is_private) { - item_id = $3 - label = shorten_left(item_id, 60) - printf "[1|%s|%s/details/%s|%s|%s]\n", label, - cgipath, item_id, server, port + id = $3 + numfound++ + if (length(query) == 0) { + query = id + } else { + query = query "+OR+" id + } + } + } + } + close(cmd) + unlink(iaout) + + # get metadata of list member items + + name_slug = uri_encode(name) + gsub(/%20/, "-", name_slug) + client_url = api_ssl_endpoint "/details/" acct "/lists/" list_id \ + "/" name_slug + url = api_ssl_endpoint "/services/search/beta/page_production/" \ + "?user_query=identifier:(" query ")" \ + "&hits_per_page=" rows \ + "&page=" page \ + "&aggregations=false" \ + "&client_url=" client_url + api_request(url, "GET", iaout) + + pages = int(numfound / rows) + if (numfound % rows != 0) { + pages++ + } + + # format as a gopher directory (menu) + + printf "# List: %s, page %d of %d\n", name, page, pages + print "" + + cmd = sprintf("%s <%s 2>&1", cmd_json2tsv, iaout) + FS = "\t" + count = 0 + creator = "" + id = "" + title = "" + type = "" + while ((cmd | getline) > 0) { + if ($1 == ".response.body.hits.hits[].fields.creator[]" && + $2 == "s" && length(creator) == 0) + { + creator = $3 + } else if ($1 == ".response.body.hits.hits[].fields.identifier" && + $2 == "s") + { + id = $3 + } else if ($1 == ".response.body.hits.hits[].fields.mediatype" && + $2 == "s") + { + type = $3 + } else if ($1 == ".response.body.hits.hits[].fields.title" && + $2 == "s") + { + title = $3 + } else if ($1 == ".response.body.hits.hits[]._score" && $2 == "a") { + # the _score field happens to be toward the end of each item + if (length(title) > 0) { + if (length(creator) > 0) { + label = sprintf("[%s] %s by %s", mediatype[type], \ + gph_encode(shorten(title, 40)), shorten(creator, 18)) + } else { + label = sprintf("[%s] %s", mediatype[type], \ + gph_encode(shorten(title, 58))) + } + printf "[1|%s|%s/details/%s|%s|%s]\n", label, cgipath, id, + server, port + count++ } + creator = "" + descr = "" + id = "" + type = "" } } close(cmd) + # only show "page back" if the user is past page 1 + if (page > 1) { + printf "[1|[<<] Page %d|%s/list/page%d/rows%d/%%09%s/%d|%s|%s]\n", + page - 1, cgipath, page - 1, rows, + acct, list_id, server, port + } + + # only show "next page" if the current page is completely full + if (count == rows) { + printf "[1|[>>] Page %d|%s/list/page%d/rows%d/%%09%s/%d|%s|%s]\n", + page + 1, cgipath, page + 1, rows, + acct, list_id, server, port + } + + print "" + printf "[1|Account %s|%s/account/%s|%s|%s]\n", acct, cgipath, + acct, server, port + print "" printf "[1|PHAROS|%s|%s|%s]\n", cgipath, server, port unlink(iaout) exit 0 @@ -64,7 +169,8 @@ BEGIN { config_init() cgi_init() uri_encode_init() + util_init() main() } Index: src/search/index.dcgi.m4 ================================================================== --- src/search/index.dcgi.m4 +++ src/search/index.dcgi.m4 @@ -12,20 +12,10 @@ function main(search, cmd, count, creator, descr, field, fields, i, \ iaout, id, jsout, label, numfound, order, orders, page, rows, \ searchstr, title, type, url) { - mediatype["audio"] = "aud" - mediatype["collection"] = "col" - mediatype["data"] = "dat" - mediatype["etree"] = "aud" - mediatype["image"] = "img" - mediatype["movies"] = "mov" - mediatype["software"] = "bin" - mediatype["texts"] = "txt" - mediatype["web"] = "web" - rows = 15 page = 1 delete order orders = 0 @@ -144,10 +134,11 @@ } else if ($1 == ".response.docs[].identifier" && $2 == "s") { id = $3 } else if ($1 == ".response.docs[].mediatype" && $2 == "s") { type = $3 } else if ($1 == ".response.docs[].title" && $2 == "s") { + # the title field happens to be toward the end of each item title = $3 count++ if (length(creator) > 0) { label = sprintf("[%s] %s by %s", mediatype[type], \ gph_encode(shorten(title, 40)), shorten(creator, 18)) Index: src/util.awk ================================================================== --- src/util.awk +++ src/util.awk @@ -166,10 +166,20 @@ "Attribution-NonCommercial 4.0 International" licenseurl["https://creativecommons.org/licenses/by-nc-sa/4.0/"] = \ "Attribution-NonCommercial-ShareAlike 4.0 International" licenseurl["https://creativecommons.org/licenses/by-nc-nd/4.0/"] = \ "Attribution-NonCommercial-NoDerivs 4.0 International" + + mediatype["audio"] = "aud" + mediatype["collection"] = "col" + mediatype["data"] = "dat" + mediatype["etree"] = "aud" + mediatype["image"] = "img" + mediatype["movies"] = "mov" + mediatype["software"] = "bin" + mediatype["texts"] = "txt" + mediatype["web"] = "web" size_kb = 1024 size_mb = 1024 * 1024 size_gb = 1024 * 1024 * 1024 return