diff options
Diffstat (limited to 'lib/lsg_irc/link_plugin.ex')
-rw-r--r-- | lib/lsg_irc/link_plugin.ex | 130 |
1 files changed, 109 insertions, 21 deletions
diff --git a/lib/lsg_irc/link_plugin.ex b/lib/lsg_irc/link_plugin.ex index bc9764a..97835e4 100644 --- a/lib/lsg_irc/link_plugin.ex +++ b/lib/lsg_irc/link_plugin.ex @@ -39,7 +39,7 @@ defmodule LSG.IRC.LinkPlugin do require Logger def start_link() do - GenServer.start_link(__MODULE__, []) + GenServer.start_link(__MODULE__, [], name: __MODULE__) end @callback match(uri :: URI.t, options :: Keyword.t) :: {true, params :: Map.t} | false @@ -49,6 +49,7 @@ defmodule LSG.IRC.LinkPlugin do def init([]) do {:ok, _} = Registry.register(IRC.PubSub, "message", []) + #{:ok, _} = Registry.register(IRC.PubSub, "message:telegram", []) Logger.info("Link handler started") {:ok, %__MODULE__{}} end @@ -66,7 +67,12 @@ defmodule LSG.IRC.LinkPlugin do [uri] -> text [uri | _] -> ["-> #{URI.to_string(uri)}", text] end - message.replyfun.(text) + IO.inspect(text) + if is_list(text) do + for line <- text, do: message.replyfun.(line) + else + message.replyfun.(text) + end _ -> nil end end) @@ -91,8 +97,8 @@ defmodule LSG.IRC.LinkPlugin do # 4. ? # Over five redirections: cancel. - def expand_link([_, _, _, _, _, _ | _]) do - :error + def expand_link(acc = [_, _, _, _, _ | _]) do + {:ok, acc, "link redirects more than five times"} end def expand_link(acc=[uri | _]) do @@ -128,14 +134,14 @@ defmodule LSG.IRC.LinkPlugin do end defp get(url, headers \\ [], options \\ []) do - get_req(:hackney.get(url, headers, <<>>, options)) + get_req(url, :hackney.get(url, headers, <<>>, options)) end - defp get_req({:error, reason}) do + defp get_req(_, {:error, reason}) do {:error, reason} end - defp get_req({:ok, 200, headers, client}) do + defp get_req(url, {:ok, 200, headers, client}) do headers = Enum.reduce(headers, %{}, fn({key, value}, acc) -> Map.put(acc, String.downcase(key), value) end) @@ -145,14 +151,14 @@ defmodule LSG.IRC.LinkPlugin do cond do String.starts_with?(content_type, "text/html") && length <= 30_000_000 -> - get_body(30_000_000, client, <<>>) + get_body(url, 30_000_000, client, <<>>) true -> :hackney.close(client) {:ok, "file: #{content_type}, size: #{length} bytes"} end end - defp get_req({:ok, redirect, headers, client}) when redirect in 300..399 do + defp get_req(_, {:ok, redirect, headers, client}) when redirect in 300..399 do headers = Enum.reduce(headers, %{}, fn({key, value}, acc) -> Map.put(acc, String.downcase(key), value) end) @@ -162,32 +168,70 @@ defmodule LSG.IRC.LinkPlugin do {:redirect, location} end - defp get_req({:ok, status, headers, client}) do + defp get_req(_, {:ok, status, headers, client}) do :hackney.close(client) {:error, status, headers} end - defp get_body(len, client, acc) when len >= byte_size(acc) do + defp get_body(url, len, client, acc) when len >= byte_size(acc) do case :hackney.stream_body(client) do {:ok, data} -> - get_body(len, client, << acc::binary, data::binary >>) + get_body(url, len, client, << acc::binary, data::binary >>) :done -> html = Floki.parse(acc) - title = case Floki.find(html, "title") do - [{"title", [], [title]} | _] -> - String.trim(title) - _ -> - nil + title = collect_title(html) + opengraph = collect_open_graph(html) + itemprops = collect_itemprops(html) + Logger.debug("OG: #{inspect opengraph}") + text = if Map.has_key?(opengraph, "title") && Map.has_key?(opengraph, "description") do + sitename = if sn = Map.get(opengraph, "site_name") do + "#{sn}" + else + "" + end + paywall? = if Map.get(opengraph, "article:content_tier", Map.get(itemprops, "article:content_tier", "free")) == "free" do + "" + else + "[paywall] " + end + section = if section = Map.get(opengraph, "article:section", Map.get(itemprops, "article:section", nil)) do + ": #{section}" + else + "" + end + date = case DateTime.from_iso8601(Map.get(opengraph, "article:published_time", Map.get(itemprops, "article:published_time", ""))) do + {:ok, date, _} -> + "#{Timex.format!(date, "%d/%m/%y", :strftime)}. " + _ -> + "" + end + uri = URI.parse(url) + + prefix = "#{paywall?}#{Map.get(opengraph, "site_name", uri.host)}#{section}" + prefix = unless prefix == "" do + "#{prefix} — " + else + "" + end + [clean_text("#{prefix}#{Map.get(opengraph, "title")}")] ++ IRC.splitlong(clean_text("#{date}#{Map.get(opengraph, "description")}")) + else + clean_text(title) end - {:ok, title} + {:ok, text} {:error, reason} -> {:ok, "failed to fetch body: #{inspect reason}"} end end + defp clean_text(text) do + text + |> String.replace("\n", " ") + |> HtmlEntities.decode() + end + defp get_body(len, client, _acc) do :hackney.close(client) - {:ok, "mais il rentrera jamais en ram ce fichier !"} + {:ok, "Error: file over 30"} end def expand_default(acc = [uri = %URI{scheme: scheme} | _]) when scheme in ["http", "https"] do @@ -201,9 +245,10 @@ defmodule LSG.IRC.LinkPlugin do new_uri = %URI{new_uri | scheme: scheme, authority: uri.authority, host: uri.host, port: uri.port} expand_link([new_uri | acc]) {:error, status, _headers} -> - {:ok, acc, "Error #{status}"} + text = Plug.Conn.Status.reason_phrase(status) + {:ok, acc, "Error: HTTP #{text} (#{status})"} {:error, reason} -> - {:ok, acc, "Error #{to_string(reason)}"} + {:ok, acc, "Error: #{to_string(reason)}"} end end @@ -212,4 +257,47 @@ defmodule LSG.IRC.LinkPlugin do {:ok, [uri], "-> #{URI.to_string(uri)}"} end + defp collect_title(html) do + case Floki.find(html, "title") do + [{"title", [], [title]} | _] -> + String.trim(title) + _ -> + nil + end + end + + defp collect_open_graph(html) do + Enum.reduce(Floki.find(html, "head meta"), %{}, fn(tag, acc) -> + case tag do + {"meta", values, []} -> + name = List.keyfind(values, "property", 0, {nil, nil}) |> elem(1) + content = List.keyfind(values, "content", 0, {nil, nil}) |> elem(1) + case name do + "og:" <> key -> + Map.put(acc, key, content) + "article:"<>_ -> + Map.put(acc, name, content) + _other -> acc + end + _other -> acc + end + end) + end + + defp collect_itemprops(html) do + Enum.reduce(Floki.find(html, "[itemprop]"), %{}, fn(tag, acc) -> + case tag do + {"meta", values, []} -> + name = List.keyfind(values, "itemprop", 0, {nil, nil}) |> elem(1) + content = List.keyfind(values, "content", 0, {nil, nil}) |> elem(1) + case name do + "article:" <> key -> + Map.put(acc, name, content) + _other -> acc + end + _other -> acc + end + end) + end + end |