local json = require("cjson") pleroma_avatar_save_path = nil -- location of downloaded images pleroma_avatar_path = nil -- prepended to image file, written on page -- to configure, put above vars in a file named 'config.lua' pcall( function () dofile("config.lua") end ) --[[ if these variables are still `nil` after `dofile()` then the script will look for it in the yaml header. note: lua filters can not access variables defined on the command line, e.g `pandoc -V foo="bar"` and it may not be ideal to define paths in yaml headers, i.e changing the path for avatars on a website would involve editing each manuscript. ]]-- -- for testing function printTable(t) if t then for key, value in pairs(t) do print(key, value) end end end function add_unique(list, item) if type(list) ~= "table" or item == nil then -- print("item "..item) return false end for _, value in ipairs(list) do if value == item then return false end end table.insert(list, item) -- print("added "..item) return true end function tokenizeString(inputString, delimiter) local tokens = {} for token in inputString:gmatch("[^" .. delimiter .. "]+") do table.insert(tokens, token) end return tokens end function get(link, filename) print("http/s GET: ".. link) local filename = filename or nil local args = {} if filename then args = { "--timeout=10", "-qO", filename, link } else args = { "-qO-", "--timeout=10", link } end local command = "wget " .. table.concat(args, ' ') local success, retval = pcall( function () -- print("!: ".. table.concat(args)) return pandoc.pipe("wget", args, "") end ) if not success then print("warning: error while performing http/s GET") print(retval) end return retval end function get_epoch_time(timestamp) local pattern = "(%d+)-(%d+)-(%d+)T(%d+):(%d+):(%d+).000Z" local year, month, day, hour, min, sec = timestamp:match(pattern) local epoch = os.time({ year = year, month = month, day = day, hour = hour, min = min, sec = sec }) return epoch end function get_short_date(timestamp) return os.date( "%a, %B %d, %Y", get_epoch_time(timestamp) ) end function write_comments(pleroma_posts, instance, avatar_path) local avatar_mode = 1 if avatar_path then avatar_mode = 2 end -- img mode : 0 = omit; 1 = display (hotlink); 2 = download function get_user(acct_data, instance, img_mode, folder) -- specify path to store avatars -- should be empty string if img_mode != 2 local folder = folder or "" -- related to output local user_info = "" -- template local result = "" local vars = { alias = acct_data["display_name"], uid = acct_data["id"], handle = acct_data["acct"], host=instance } local filename = nil local avatar_url = acct_data["avatar_static"] if img_mode then user_info = [[
avatar
$alias$ @$handle$
]] if img_mode == 1 then vars.avatar = acct_data["avatar_static"] else -- save to file such as user_at_instance_tld.png -- omit query e.g ?name="foo" - get the extension only local extension = (avatar_url:match("([^?]+)")):match("^.+(%..+)$") -- replace '@'s and '.' local name = (acct_data["acct"]:gsub("@", "_at_")):gsub("%.", "_") filename = name .. extension vars.avatar = folder .. filename end result = user_info:gsub("%$(%w+)%$", vars) else user_info = "

$a`lias$ @$handle$

" result = user_info:gsub("%$(%w+)%$", vars) end -- print("vars: " .. vars.avatar) return result, filename, avatar_url end function get_card(card, instance) if card == nil or type(card) ~= "table" then return "" end if card["provider_url"] == instance then -- skip rendering a card return "" end -- print(type(card)) local card_template = [[

$title$

$description$

]] local vars = { title = card["title"], description = card["description"], image = card["image"], image_description=card["image_description"], link = card["url"] } return card_template:gsub("%$(%w+)%$", vars) end function get_media(attachments) if type(attachments) ~= "table" then return "" end if #attachments < 1 then return "" end local media_list = {"

media attached:

    "} local item = "
  1. $mime$
  2. " for _, v in pairs(attachments) do local vars = { link = v["preview_url"], mime = v["pleroma"]["mime_type"] } local foo = item:gsub("%$(%w+)%$", vars) -- print(foo) table.insert(media_list, foo) end table.insert(media_list, "
") return table.concat(media_list, "\n") end function get_poll(poll) if type(poll) ~= "table" then return "" end local bar_chart = {"
"} local bar_template = [[
$pct$%
$label$
]] local total_votes = math.floor(poll["votes_count"]) local total_voters = math.floor(poll["voters_count"]) for _, v in pairs(poll["options"]) do local percentage = (v["votes_count"]/total_votes) * 100 local rounded = math.floor(0.5 + percentage) local vars = { label = v["title"], pct = rounded } local bar = bar_template:gsub("%$(%w+)%$", vars) table.insert(bar_chart, bar) end -- close chart div table.insert(bar_chart, "
") local summary = "

$x$ people have cast $y$ votes

" local foo = summary:gsub( "%$(%w+)%$", {x=total_voters, y=total_votes} ) table.insert(bar_chart, foo) return table.concat(bar_chart,"\n") end if #pleroma_posts == 0 then return "" end local template = [[

#$i$ $datetime$

$user$
$text$
$card$ $attributes$
]] local comments = {} local replies = pleroma_posts-- ["descendants"] local links = {} local images = {} for i, post in ipairs(replies) do local pid = post["id"] local datetime = get_short_date(post["created_at"]) local text = post["content"] local attrs = {} table.insert( attrs, get_media(post["media_attachments"]) ) table.insert(attrs, get_poll(post["poll"])) local user, img_file, img_url = get_user( post["account"], instance, avatar_mode, avatar_path) add_unique(images, img_file) add_unique(links, img_url) local interpolated = template:gsub("%$(%w+)%$", { i= #replies - i + 1, host=instance, pid=pid, datetime=datetime, user=user, text = text, card = get_card(post["card"], instance), attributes = table.concat(attrs) }) -- print(interpolated) table.insert( comments, pandoc.RawBlock("html", interpolated) ) end -- printTable(dl_list) return comments, images, links end function combine_tables(a,b) -- iterate through b, add to a for i=1,#b do table.insert(a, b[i]) end return a end function get_url_from_pandoc_str(pandoc_str) local str = pandoc.utils.stringify(pandoc_str) -- 1 = protocol, 2 = host ... -- https://host.tld/notice/12345 local tokens = tokenizeString(str, '/') local id = tokens[#tokens] local host = tokens[2] local id = tokens[#tokens] local link = str return link, host, id end function get_status(host, post_id) local url = "https://" .. host .. "/api/v1/statuses/" .. post_id -- print(url) return json.decode(get(url)) end function get_replies(host, id) local url = "https://" .. host .. "/api/v1/statuses/" .. id .. "/context" -- print(url) local got = json.decode(get(url)) return got["descendants"] end function get_images(filenames, urls, folder) if not folder then folder = "" end if not filenames or not urls then return end if #filenames ~= #urls then return end for i = 1, #urls, 1 do -- still possible to have a ilst of nil (file names) if not filenames[i] then break end get(urls[i], folder .. filenames[i]) end end function Meta(meta) local pleroma_urls = meta["pleroma-urls"] if pleroma_urls == nil then return -- abort end -- if both are defined, then do not hotlink avatars if not pleroma_avatar_save_path then pleroma_avatar_save_path = meta["pleroma-avatar-save-path"] end if not pleroma_avatar_path then pleroma_avatar_path = meta["pleroma-avatar-path"] end -- most servers appear to serve hotilnked avatars however -- images will be missing in case of downtime or shutdown -- OR a user has changed their avatar and the old avatar gets deleted -- var currently unused -- local is_hotlink = true -- if pleroma_avatar_save_path and pleroma_avatar_path then -- is_hotlink = false -- end local all_replies = {} local hrefs = {} local host = "" -- for each listed url in "pleroma-urls" for _, v in pairs(pleroma_urls) do local link, domain, id = get_url_from_pandoc_str(v) host = domain table.insert(hrefs, {link = link, id = id} ) local op = get_status(host, id) table.insert(all_replies, op) local replies = get_replies(host, id) combine_tables(all_replies, replies) end table.sort(all_replies, function(a, b) local ta = get_epoch_time(a["created_at"]) local tb = get_epoch_time(b["created_at"]) return ta > tb end ) -- returns comments, images, links (img urls) local c, i, l = write_comments( all_replies, "https://" .. host, pleroma_avatar_path ) get_images(i, l, pleroma_avatar_save_path) meta["pleroma-comments"] = c meta["pleroma-comments-count"] = #c meta["pleroma-has-comments"] = (#c > 0) meta["pleroma"] = hrefs return meta end