peertube-plugin-livechat/prosody-modules/mod_vcard_peertubelivechat/mod_vcard_peertubelivechat.lua

135 lines
4.7 KiB
Lua
Raw Normal View History

local st = require "util.stanza";
local http = require "net.http";
2022-01-05 18:17:40 +00:00
local gettime = require 'socket'.gettime;
local async = require "util.async";
local b64 = require "util.encodings".base64.encode;
local jid_split = require "util.jid".split;
local json = require "util.json";
local uh = require "util.http";
module:add_feature("vcard-temp");
2022-01-05 18:17:40 +00:00
local CACHE_EXPIRY = 3600;
local cache_user = {};
local peertube_url = assert(module:get_option_string("peertubelivechat_vcard_peertube_url", nil), "'peertubelivechat_vcard_peertube_url' is a required option");
if peertube_url:sub(-1,-1) == "/" then peertube_url = peertube_url:sub(1,-2); end
local function get_avatar_url(ret)
-- Note:
-- * before Peertube v6.0.0: using ret.avatar
-- * after Peertube v6.0.0: using ret.avatars, searching for width 48, or for the smallest width
if ret.avatar and ret.avatar.path then
module:log("debug", "User avatar path (Peertube < v6): %s", peertube_url .. ret.avatar.path);
return peertube_url .. ret.avatar.path;
end
local min_width = 100000;
local min_path = nil;
if ret.avatars and type(ret.avatars) == "table" then
for _, avatar in ipairs(ret.avatars) do
if avatar.path and avatar.width then
if (avatar.width == 48) then
module:log("debug", "User avatar path (Peertube >= v6, width 48): %s", peertube_url .. avatar.path);
return peertube_url .. avatar.path;
end
if (avatar.width < min_width) then;
min_path = avatar.path;
min_width = avatar.width;
end
end
end
if min_path then
module:log("debug", "User avatar path (Peertube >= v6, minimal width): %s", peertube_url .. min_path);
return peertube_url .. min_path;
end
end
module:log("debug", "Cant find user avatar url");
return nil;
end
module:hook("iq-get/bare/vcard-temp:vCard", function (event)
local origin, stanza = event.origin, event.stanza;
local who = jid_split(stanza.attr.to) or origin.username
module:log("debug", "vCard request for %s", who);
2022-01-05 18:17:40 +00:00
local from_cache = cache_user[who];
if from_cache then
if from_cache["last_fetch_time"] and from_cache["last_fetch_time"] + CACHE_EXPIRY < gettime() then
module:log("debug", "vCard result for %s was in cache but is expired.", who);
cache_user[who] = nil
else
module:log("debug", "vCard result for %s is in cache.", who);
if (from_cache['vcard']) then
origin.send(st.reply(stanza):add_child(from_cache["vcard"]));
else
origin.send(st.error_reply(stanza, "cancel", "item-not-found"));
end
return true;
end
else
module:log("debug", "vCard result for %s is not in cache.", who);
end
local wait, done = async.waiter();
local url = peertube_url .. '/api/v1/accounts/' .. uh.urlencode(who);
module:log("debug", "Calling Peertube API: %s", url);
local ret;
http.request(url, { accept = "application/json" }, function (body, code)
if math.floor(code / 100) == 2 then
local parsed, parse_err = json.decode(body);
if not parsed then
module:log("debug", "Got invalid JSON from %s: %s", url, parse_err);
else
ret = parsed;
end
else
module:log("debug", "Rejected by API: ", body);
end
done();
end)
wait();
if not ret then
module:log("debug", "Peertube user not found, no vCard for %s", who);
origin.send(st.error_reply(stanza, "cancel", "item-not-found"));
2022-01-05 18:17:40 +00:00
cache_user[who] = { last_fetch_time = gettime() };
return true;
end
2022-01-05 19:13:59 +00:00
local vcard_temp = st.stanza("vCard", { xmlns = "vcard-temp" });
2022-01-05 18:23:20 +00:00
vcard_temp:text_tag("FN", ret.displayName);
vcard_temp:text_tag("NICKNAME", ret.displayName);
2022-01-05 19:11:22 +00:00
vcard_temp:text_tag("URL", ret.url);
2022-01-05 19:13:59 +00:00
local avatar_url = get_avatar_url(ret);
if avatar_url then
-- module:log("debug", "Downloading user avatar on %s", avatar_url);
local waitAvatar, doneAvatar = async.waiter();
http.request(avatar_url, {}, function (body, code, response)
if math.floor(code / 100) == 2 then
module:log("debug", "Avatar found for %s", who);
2022-01-06 02:29:52 +00:00
vcard_temp:tag("PHOTO");
2022-01-05 19:11:22 +00:00
if (response and response.headers and response.headers["content-type"]) then
module:log("debug", "Avatar content-type: %s", response.headers["content-type"]);
2022-01-06 02:29:52 +00:00
vcard_temp:text_tag("TYPE", response.headers["content-type"]);
vcard_temp:text_tag("BINVAL", b64(body));
vcard_temp:up();
2022-01-05 19:11:22 +00:00
else
module:log("debug", "Avatar has no content-type.");
end
else
module:log("debug", "Cant load avatar: ", body);
end
doneAvatar();
end)
waitAvatar();
end
origin.send(st.reply(stanza):add_child(vcard_temp));
2022-01-05 18:17:40 +00:00
cache_user[who] = { last_fetch_time = gettime(), vcard = vcard_temp };
return true;
2022-01-05 19:13:59 +00:00
end);