defmodule Nola.IRC.OutlinePlugin do
@moduledoc """
# outline auto-link
Envoie un lien vers Outline quand un lien est envoyé.
* **!outline `<url>`** crée un lien outline pour `<url>`.
* **+outline `<host>`** active outline pour `<host>`.
* **-outline `<host>`** désactive outline pour `<host>`.
"""
def short_irc_doc, do: false
def irc_doc, do: @moduledoc
require Logger
def start_link() do
GenServer.start_link(__MODULE__, [], name: __MODULE__)
end
defstruct [:file, :hosts]
def init([]) do
regopts = [plugin: __MODULE__]
{:ok, _} = Registry.register(IRC.PubSub, "trigger:outline", regopts)
{:ok, _} = Registry.register(IRC.PubSub, "messages", regopts)
file = Path.join(Nola.data_path, "/outline.txt")
hosts = case File.read(file) do
{:error, :enoent} ->
[]
{:ok, lines} ->
String.split(lines, "\n", trim: true)
end
{:ok, %__MODULE__{file: file, hosts: hosts}}
end
def handle_info({:irc, :trigger, "outline", message = %IRC.Message{trigger: %IRC.Trigger{type: :plus, args: [host]}}}, state) do
state = %{state | hosts: [host | state.hosts]}
save(state)
message.replyfun.("ok")
{:noreply, state}
end
def handle_info({:irc, :trigger, "outline", message = %IRC.Message{trigger: %IRC.Trigger{type: :minus, args: [host]}}}, state) do
state = %{state | hosts: List.delete(state.hosts, host)}
save(state)
message.replyfun.("ok")
{:noreply, state}
end
def handle_info({:irc, :trigger, "outline", message = %IRC.Message{trigger: %IRC.Trigger{type: :bang, args: [url]}}}, state) do
line = "-> #{outline(url)}"
message.replyfun.(line)
end
def handle_info({:irc, :text, message = %IRC.Message{text: text}}, state) do
String.split(text)
|> Enum.map(fn(word) ->
if String.starts_with?(word, "http://") || String.starts_with?(word, "https://") do
uri = URI.parse(word)
if uri.scheme && uri.host do
if Enum.any?(state.hosts, fn(host) -> String.ends_with?(uri.host, host) end) do
outline_url = outline(word)
line = "-> #{outline_url}"
message.replyfun.(line)
end
end
end
end)
{:noreply, state}
end
def handle_info(msg, state) do
{:noreply, state}
end
def save(state = %{file: file, hosts: hosts}) do
string = Enum.join(hosts, "\n")
File.write(file, string)
end
def outline(url) do
unexpanded = "https://outline.com/#{url}"
headers = [
{"User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:77.0) Gecko/20100101 Firefox/77.0"},
{"Accept", "*/*"},
{"Accept-Language", "en-US,en;q=0.5"},
{"Origin", "https://outline.com"},
{"DNT", "1"},
{"Referer", unexpanded},
{"Pragma", "no-cache"},
{"Cache-Control", "no-cache"}
]
params = %{"source_url" => url}
case HTTPoison.get("https://api.outline.com/v3/parse_article", headers, params: params) do
{:ok, %HTTPoison.Response{status_code: 200, body: json}} ->
body = Poison.decode!(json)
if Map.get(body, "success") do
code = get_in(body, ["data", "short_code"])
"https://outline.com/#{code}"
else
unexpanded
end
error ->
Logger.info("outline.com error: #{inspect error}")
unexpanded
end
end
end