HomingPigeon/lib/formatter.ex

187 lines
4.2 KiB
Elixir
Executable File

defmodule Discordirc.Formatter do
@moduledoc """
Transforms messages to/from discord from/to irc
"""
alias Nostrum.Api, as: DiscordAPI
def from_irc(nick, msg, ctcp \\ false) do
# strip or replace IRC formatting.
fmsg =
msg
|> :re.replace("\x02(.*?)\x02", "**\\g1**", [:global])
|> :re.replace("\x02(.*)", "**\\g1**")
|> :re.replace("\x01|\x03[0123456789]*(,[0123456789]*)?", "", [:global])
case ctcp do
true ->
case fmsg do
x when is_binary(x) -> "_#{x}_"
x when is_list(x) -> "_#{List.to_string(x)}_"
end
false ->
case fmsg do
x when is_binary(x) -> "#{x}"
x when is_list(x) -> "#{List.to_string(x)}"
end
end
end
defmodule DiscordUserInfo do
defstruct id: nil, username: nil, discriminator: nil, nickname: nil
def from_id(id, guild) do
case DiscordAPI.get_user(id) do
{:ok, user} ->
case DiscordAPI.get_guild_member(guild, user.id()) do
{:error, _} ->
nil
{:ok, member} ->
%DiscordUserInfo{
id: id,
username: user.username,
discriminator: user.discriminator,
nickname: member.nick
}
end
{:error, _} ->
nil
end
end
end
defmodule DiscordChannelInfo do
defstruct id: nil, channel: nil
def from_id(id) do
case DiscordAPI.get_channel(id) do
{:ok, channel} ->
%DiscordChannelInfo{
id: id,
channel: channel.name
}
{:error, _} ->
nil
end
end
end
def tryreplace(s, m) do
case m do
%{dui: nil} ->
s
%{cui: nil} ->
s
%{str: r, dui: dui} ->
if String.match?(s, ~r/\<\@(\d+)\>/) do
if s == r do
if is_binary(dui.nickname) do
String.replace(s, r, "@" <> dui.nickname)
else
String.replace(s, r, "@" <> dui.username <> "#" <> dui.discriminator)
end
else
nil
end
else
s
end
%{str: r, cui: cui} ->
if String.match?(s, ~r/\<#(\d+)\>/) do
if s == r do
String.replace(s, r, "#" <> cui.channel)
else
nil
end
else
s
end
end
end
def doallreplacements(split, matches, acc) do
[shead | stail] = split
{str, [m | mtail]} = acc
s = tryreplace(shead, m)
if is_nil(s) do
doallreplacements(split, matches, {str, mtail})
else
if stail == [] do
str <> s
else
doallreplacements(stail, matches, {str <> s, matches})
end
end
end
def fixdiscordidstrings(%{:content => content, :guild_id => guild}) do
pattern = ~r/\<(\@!?|#)(\d+)\>/um
matches =
Regex.scan(pattern, content)
|> Enum.uniq()
|> Enum.map(fn
[fst, "@", lst] ->
%{str: fst, id: lst, dui: DiscordUserInfo.from_id(String.to_integer(lst), guild)}
[fst, "@!", lst] ->
%{str: fst, id: lst, dui: DiscordUserInfo.from_id(String.to_integer(lst), guild)}
[fst, "#", lst] ->
%{str: fst, id: lst, cui: DiscordChannelInfo.from_id(String.to_integer(lst))}
end)
if matches == [] do
content
else
doallreplacements(
Regex.split(pattern, content, include_captures: true),
matches,
{"", matches}
)
end
end
def from_discord(msg) do
%{attachments: attachments, author: user, guild_id: guild} = msg
usr =
case DiscordAPI.get_guild_member(guild, user.id) do
{:ok, %{nick: nick}} when is_binary(nick) -> nick
_ -> "#{user.username}\##{user.discriminator}"
end
cpart =
msg
|> fixdiscordidstrings
|> String.split("\n")
apart =
attachments
|> Enum.map(& &1.url)
messages =
(cpart ++ apart)
|> Enum.filter(&(&1 != ""))
# discord may give... many lines. split and format.
case Enum.count(messages) do
0 ->
{usr, "#{messages[0]}"}
_ ->
{usr,
messages
|> Enum.map(fn m -> "#{m}" end)}
end
end
end