# HG changeset patch # User Matthew Wild # Date 1569772077 -3600 # Node ID 47e1c94fb6fbb66a42254839b7a0af17946cf33d # Parent d267e381255fb456fc86baa9868b55f110452885 mod_muc_media_metadata: Module to automatically fetch metadata for posted media diff -r d267e381255f -r 47e1c94fb6fb mod_muc_media_metadata/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_muc_media_metadata/README.md Sun Sep 29 16:47:57 2019 +0100 @@ -0,0 +1,38 @@ +# Introduction + +This module adds additional metadata to media shared in a MUC. This can help clients +make decisions and provide better UI and enhanced privacy, by knowing things like file +size without needing to make external network requests. + +# Configuring + +## Enabling + +``` {.lua} +Component "rooms.example.net" "muc" +modules_enabled = { + "muc_hide_media"; +} +``` + +## Settings + +There are no configuration options for this module. + +# Developers + +Example stanza: + +``` + + https://matthewwild.co.uk/share.php/70334772-ff74-439b-8173-a71e40ca28db/mam-flow.png + + https://matthewwild.co.uk/share.php/70334772-ff74-439b-8173-a71e40ca28db/mam-flow.png + + 15690 + image/png + LEHV6nWB2yk8pyo0adR*.7kCMdnj + + + +``` diff -r d267e381255f -r 47e1c94fb6fb mod_muc_media_metadata/mod_muc_media_metadata.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_muc_media_metadata/mod_muc_media_metadata.lua Sun Sep 29 16:47:57 2019 +0100 @@ -0,0 +1,61 @@ +local async = require "util.async"; +local promise = require "util.promise"; +local http = require "net.http"; +local st = require "util.stanza"; + +local xmlns_metadata = "https://prosody.im/protocol/media-metadata#0" + +local fetch_headers = { + bytes = "content-length"; + type = "content-type"; + etag = "etag"; + blurhash = "blurhash"; +}; + +local function fetch_media_metadata(url) + return promise.new(function (resolve) + http.request(url, { method = "HEAD" }, function (body, code, response) --luacheck: ignore 212/body + if code == 200 then + local metadata = {}; + for metadata_name, header_name in pairs(fetch_headers) do + metadata[metadata_name] = response.headers[header_name]; + end + resolve(metadata); + else + resolve(nil); + end + end); + end); +end + +local function metadata_to_tag(metadata) + if not metadata then return; end + + local metadata_tag = st.stanza("metadata", { xmlns = xmlns_metadata }); + for k, v in pairs(metadata) do + metadata_tag:text_tag(k, v) + end + + return metadata_tag; +end + +module:hook("muc-occupant-groupchat", function (event) + local stanza = event.stanza; + + local promises; + + for oob in stanza:childtags("x", "jabber:x:oob") do + if not promises then promises = {}; end + local url = oob:get_child_text("url"); + local p = fetch_media_metadata(url) + :next(metadata_to_tag) + :next(function (metadata_tag) + oob:add_child(metadata_tag); + end); + table.insert(promises, p); + end + + if not promises then return; end + + async.wait(promise.all(promises)); +end);