diff options
Diffstat (limited to 'lib/plugins/link')
-rw-r--r-- | lib/plugins/link/github.ex | 18 | ||||
-rw-r--r-- | lib/plugins/link/image.ex | 110 | ||||
-rw-r--r-- | lib/plugins/link/img_debrid_link.ex | 16 | ||||
-rw-r--r-- | lib/plugins/link/imgur.ex | 37 | ||||
-rw-r--r-- | lib/plugins/link/pdf.ex | 24 | ||||
-rw-r--r-- | lib/plugins/link/redacted.ex | 6 | ||||
-rw-r--r-- | lib/plugins/link/reddit.ex | 149 | ||||
-rw-r--r-- | lib/plugins/link/scraper.ex | 39 | ||||
-rw-r--r-- | lib/plugins/link/store.ex | 1 | ||||
-rw-r--r-- | lib/plugins/link/twitter.ex | 127 | ||||
-rw-r--r-- | lib/plugins/link/youtube.ex | 53 |
11 files changed, 361 insertions, 219 deletions
diff --git a/lib/plugins/link/github.ex b/lib/plugins/link/github.ex index 77fa81f..fcd76a0 100644 --- a/lib/plugins/link/github.ex +++ b/lib/plugins/link/github.ex @@ -45,10 +45,14 @@ defmodule Nola.Plugins.Link.Github do end defp build_start(info) do - parts = [] - |> maybe_add(info.disabled, " (disabled)") - |> maybe_add(info.archived, " (archived)") - |> maybe_add(info.source && info.source["full_name"] != info.full_name, " (⑂ #{info.source["full_name"]})") + parts = + [] + |> maybe_add(info.disabled, " (disabled)") + |> maybe_add(info.archived, " (archived)") + |> maybe_add( + info.source && info.source["full_name"] != info.full_name, + " (⑂ #{info.source["full_name"]})" + ) "#{info.full_name}#{parts} - #{info.description}" end @@ -58,8 +62,9 @@ defmodule Nola.Plugins.Link.Github do end defp build_network(info) do - lang = info.language && "#{info.language} - " || "" - issues = info.open_issues_count && "#{info.open_issues_count} issues - " || "" + lang = (info.language && "#{info.language} - ") || "" + issues = (info.open_issues_count && "#{info.open_issues_count} issues - ") || "" + last_push = if at = info.pushed_at do {:ok, date, _} = DateTime.from_iso8601(at) @@ -67,6 +72,7 @@ defmodule Nola.Plugins.Link.Github do else "" end + "#{lang}#{issues}#{info.stargazers_count} stars - #{info.subscribers_count} watchers - #{info.forks_count} forks#{last_push}" end diff --git a/lib/plugins/link/image.ex b/lib/plugins/link/image.ex index cf3d9b0..2fb6862 100644 --- a/lib/plugins/link/image.ex +++ b/lib/plugins/link/image.ex @@ -6,7 +6,7 @@ defmodule Nola.Plugins.Link.Image do def match(_, _), do: false @impl true - def post_match(_url, "image/"<>_, _header, _opts) do + def post_match(_url, "image/" <> _, _header, _opts) do {:body, nil} end @@ -16,65 +16,77 @@ defmodule Nola.Plugins.Link.Image do def post_expand(_url, bytes, _, opts) do pil_process = Keyword.get(opts, :pil_process, {:pil, :"py@127.0.0.1"}) clip_ask_process = Keyword.get(opts, :clip_ask_process, {:clip_ask, :"py@127.0.0.1"}) - img2txt_process = Keyword.get(opts, :img2txt_process, {:image_to_text_vit_gpt2, :"py@127.0.0.1"}) - - tasks = [ - Task.async(fn -> - {:ok, pil} = GenServer.call(pil_process, {:run, bytes}) - pil = pil - |> Enum.map(fn({k, v}) -> {String.to_atom(to_string(k)), v} end) - pil - end), - Task.async(fn -> - {:ok, descr} = GenServer.call(img2txt_process, {:run, bytes}) - {:img2txt, to_string(descr)} - end), - Task.async(fn -> - {:ok, prompts} = GenServer.call(clip_ask_process, {:run, bytes}) - - prompts = prompts - |> Enum.sort_by(& elem(&1, 1), &>=/2) - |> Enum.take(3) - |> Enum.map(& to_string(elem(&1, 0))) - |> Enum.join(", ") - {:prompts, prompts} + + img2txt_process = + Keyword.get(opts, :img2txt_process, {:image_to_text_vit_gpt2, :"py@127.0.0.1"}) + + tasks = + [ + Task.async(fn -> + {:ok, pil} = GenServer.call(pil_process, {:run, bytes}) + + pil = + pil + |> Enum.map(fn {k, v} -> {String.to_atom(to_string(k)), v} end) + + pil + end), + Task.async(fn -> + {:ok, descr} = GenServer.call(img2txt_process, {:run, bytes}) + {:img2txt, to_string(descr)} + end), + Task.async(fn -> + {:ok, prompts} = GenServer.call(clip_ask_process, {:run, bytes}) + + prompts = + prompts + |> Enum.sort_by(&elem(&1, 1), &>=/2) + |> Enum.take(3) + |> Enum.map(&to_string(elem(&1, 0))) + |> Enum.join(", ") + + {:prompts, prompts} + end) + ] + |> Task.yield_many(5000) + |> Enum.map(fn {task, res} -> + res || Task.shutdown(task, :brutal_kill) end) - ] - |> Task.yield_many(5000) - |> Enum.map(fn {task, res} -> - res || Task.shutdown(task, :brutal_kill) - end) - results = Enum.into(List.flatten(for({:ok, value} <- tasks, do: value)), Map.new) + results = Enum.into(List.flatten(for({:ok, value} <- tasks, do: value)), Map.new()) img2txt = Map.get(results, :img2txt) prompts = Map.get(results, :prompts) - pil = if Map.get(results, :width) do - animated = if Map.get(results, :animated), do: " animated", else: "" - "#{Map.get(results, :width, 0)}x#{Map.get(results, :height, 0)}#{animated} — " - else - "" - end + pil = + if Map.get(results, :width) do + animated = if Map.get(results, :animated), do: " animated", else: "" + "#{Map.get(results, :width, 0)}x#{Map.get(results, :height, 0)}#{animated} — " + else + "" + end - descr = cond do - img2txt && prompts -> - "#{pil}#{prompts} — #{img2txt}" - img2txt -> - "#{pil}#{img2txt}" - prompts -> - "#{pil}#{prompts}" - pil != "" -> - "#{pil}" - true -> - nil - end + descr = + cond do + img2txt && prompts -> + "#{pil}#{prompts} — #{img2txt}" + + img2txt -> + "#{pil}#{img2txt}" + + prompts -> + "#{pil}#{prompts}" + + pil != "" -> + "#{pil}" + + true -> + nil + end if descr do {:ok, "image: #{descr}"} else :error end - end - end diff --git a/lib/plugins/link/img_debrid_link.ex b/lib/plugins/link/img_debrid_link.ex index a2972eb..b46c430 100644 --- a/lib/plugins/link/img_debrid_link.ex +++ b/lib/plugins/link/img_debrid_link.ex @@ -16,17 +16,17 @@ defmodule Nola.Plugins.Link.ImgDebridLink do @impl true def expand(_uri, %{id: ids}, _opts) do - with \ - {:ok, %HTTPoison.Response{status_code: 200, body: body}} <- HTTPoison.get("https://img.debrid-link.fr/api/v1/images/#{ids}/infos", [], []), - {:ok, %{"success" => true, "value" => values}} <- Jason.decode(body) - do - items = for %{"name" => name, "url" => %{"direct" => direct_url}} <- values do - "#{name}: #{direct_url}" - end + with {:ok, %HTTPoison.Response{status_code: 200, body: body}} <- + HTTPoison.get("https://img.debrid-link.fr/api/v1/images/#{ids}/infos", [], []), + {:ok, %{"success" => true, "value" => values}} <- Jason.decode(body) do + items = + for %{"name" => name, "url" => %{"direct" => direct_url}} <- values do + "#{name}: #{direct_url}" + end + {:ok, items} else _ -> :error end end - end diff --git a/lib/plugins/link/imgur.ex b/lib/plugins/link/imgur.ex index 9fe9354..49bbb7d 100644 --- a/lib/plugins/link/imgur.ex +++ b/lib/plugins/link/imgur.ex @@ -19,19 +19,24 @@ defmodule Nola.Plugins.Link.Imgur do def match(uri = %URI{host: "imgur.io"}, arg) do match(%URI{uri | host: "imgur.com"}, arg) end + def match(uri = %URI{host: "i.imgur.io"}, arg) do match(%URI{uri | host: "i.imgur.com"}, arg) end - def match(uri = %URI{host: "imgur.com", path: "/a/"<>album_id}, _) do + + def match(uri = %URI{host: "imgur.com", path: "/a/" <> album_id}, _) do {true, %{album_id: album_id}} end - def match(uri = %URI{host: "imgur.com", path: "/gallery/"<>album_id}, _) do + + def match(uri = %URI{host: "imgur.com", path: "/gallery/" <> album_id}, _) do {true, %{album_id: album_id}} end - def match(uri = %URI{host: "i.imgur.com", path: "/"<>image}, _) do + + def match(uri = %URI{host: "i.imgur.com", path: "/" <> image}, _) do [hash, _] = String.split(image, ".", parts: 2) {true, %{image_id: hash}} end + def match(_, _), do: false @impl true @@ -49,6 +54,7 @@ defmodule Nola.Plugins.Link.Imgur do client_id = Keyword.get(Application.get_env(:nola, :imgur, []), :client_id, "42") headers = [{"Authorization", "Client-ID #{client_id}"}] options = [] + case HTTPoison.get("https://api.imgur.com/3/image/#{image_id}", headers, options) do {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> {:ok, json} = Jason.decode(body) @@ -59,6 +65,7 @@ defmodule Nola.Plugins.Link.Imgur do width = Map.get(data, "width") size = Map.get(data, "size") {:ok, "image, #{width}x#{height}, #{size} bytes #{nsfw}#{title}"} + other -> :error end @@ -68,6 +75,7 @@ defmodule Nola.Plugins.Link.Imgur do client_id = Keyword.get(Application.get_env(:nola, :imgur, []), :client_id, "42") headers = [{"Authorization", "Client-ID #{client_id}"}] options = [] + case HTTPoison.get("https://api.imgur.com/3/album/#{album_id}", headers, options) do {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> {:ok, json} = Jason.decode(body) @@ -75,22 +83,31 @@ defmodule Nola.Plugins.Link.Imgur do title = data["title"] nsfw = data["nsfw"] nsfw = if nsfw, do: "(NSFW) - ", else: "" + if data["images_count"] == 1 do [image] = data["images"] - title = if title || data["title"] do - title = [title, data["title"]] |> Enum.filter(fn(x) -> x end) |> Enum.uniq() |> Enum.join(" — ") - "#{title} — " - else - "" - end + + title = + if title || data["title"] do + title = + [title, data["title"]] + |> Enum.filter(fn x -> x end) + |> Enum.uniq() + |> Enum.join(" — ") + + "#{title} — " + else + "" + end + {:ok, "#{nsfw}#{title}#{image["link"]}"} else title = if title, do: title, else: "Untitled album" {:ok, "#{nsfw}#{title} - #{data["images_count"]} images"} end + other -> :error end end - end diff --git a/lib/plugins/link/pdf.ex b/lib/plugins/link/pdf.ex index e91dcc2..bb14594 100644 --- a/lib/plugins/link/pdf.ex +++ b/lib/plugins/link/pdf.ex @@ -6,7 +6,7 @@ defmodule Nola.Plugins.Link.PDF do def match(_, _), do: false @impl true - def post_match(_url, "application/pdf"<>_, _header, _opts) do + def post_match(_url, "application/pdf" <> _, _header, _opts) do {:file, nil} end @@ -16,24 +16,32 @@ defmodule Nola.Plugins.Link.PDF do def post_expand(url, file, _, _) do case System.cmd("pdftitle", ["-p", file]) do {text, 0} -> - text = text - |> String.trim() + text = + text + |> String.trim() if text == "" do :error else basename = Path.basename(url, ".pdf") - text = "[#{basename}] " <> text - |> String.split("\n") + + text = + ("[#{basename}] " <> text) + |> String.split("\n") + {:ok, text} end + {_, 127} -> - Logger.error("dependency `pdftitle` is missing, please install it: `pip3 install pdftitle`.") + Logger.error( + "dependency `pdftitle` is missing, please install it: `pip3 install pdftitle`." + ) + :error + {error, code} -> - Logger.warn("command `pdftitle` exited with status code #{code}:\n#{inspect error}") + Logger.warn("command `pdftitle` exited with status code #{code}:\n#{inspect(error)}") :error end end - end diff --git a/lib/plugins/link/redacted.ex b/lib/plugins/link/redacted.ex index a7cfe74..0c14520 100644 --- a/lib/plugins/link/redacted.ex +++ b/lib/plugins/link/redacted.ex @@ -2,7 +2,10 @@ defmodule Nola.Plugins.Link.Redacted do @behaviour Nola.Plugins.Link @impl true - def match(uri = %URI{host: "redacted.ch", path: "/torrent.php", query: query = "id="<>id}, _opts) do + def match( + uri = %URI{host: "redacted.ch", path: "/torrent.php", query: query = "id=" <> id}, + _opts + ) do %{"id" => id} = URI.decode_query(id) {true, %{torrent: id}} end @@ -14,5 +17,4 @@ defmodule Nola.Plugins.Link.Redacted do def expand(_uri, %{torrent: id}, _opts) do end - end diff --git a/lib/plugins/link/reddit.ex b/lib/plugins/link/reddit.ex index 707e284..bd38084 100644 --- a/lib/plugins/link/reddit.ex +++ b/lib/plugins/link/reddit.ex @@ -6,14 +6,18 @@ defmodule Nola.Plugins.Link.Reddit do case String.split(path, "/") do ["", "r", sub, "comments", post_id, _slug] -> {true, %{mode: :post, path: path, sub: sub, post_id: post_id}} + ["", "r", sub, "comments", post_id, _slug, ""] -> {true, %{mode: :post, path: path, sub: sub, post_id: post_id}} + ["", "r", sub, ""] -> {true, %{mode: :sub, path: path, sub: sub}} + ["", "r", sub] -> {true, %{mode: :sub, path: path, sub: sub}} -# ["", "u", user] -> -# {true, %{mode: :user, path: path, user: user}} + + # ["", "u", user] -> + # {true, %{mode: :user, path: path, user: user}} _ -> false end @@ -33,32 +37,47 @@ defmodule Nola.Plugins.Link.Reddit do @impl true def expand(_, %{mode: :sub, sub: sub}, _opts) do url = "https://api.reddit.com/r/#{sub}/about" + case HTTPoison.get(url) do {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> - sr = Jason.decode!(body) - |> Map.get("data") - |> IO.inspect(limit: :infinity) - description = Map.get(sr, "public_description")||Map.get(sr, "description", "") - |> String.split("\n") - |> List.first() - name = if title = Map.get(sr, "title") do - Map.get(sr, "display_name_prefixed") <> ": " <> title - else - Map.get(sr, "display_name_prefixed") - end - nsfw = if Map.get(sr, "over18") do - "[NSFW] " - else - "" - end - quarantine = if Map.get(sr, "quarantine") do - "[Quarantined] " - else - "" - end - count = "#{Map.get(sr, "subscribers")} subscribers, #{Map.get(sr, "active_user_count")} active" + sr = + Jason.decode!(body) + |> Map.get("data") + |> IO.inspect(limit: :infinity) + + description = + Map.get(sr, "public_description") || + Map.get(sr, "description", "") + |> String.split("\n") + |> List.first() + + name = + if title = Map.get(sr, "title") do + Map.get(sr, "display_name_prefixed") <> ": " <> title + else + Map.get(sr, "display_name_prefixed") + end + + nsfw = + if Map.get(sr, "over18") do + "[NSFW] " + else + "" + end + + quarantine = + if Map.get(sr, "quarantine") do + "[Quarantined] " + else + "" + end + + count = + "#{Map.get(sr, "subscribers")} subscribers, #{Map.get(sr, "active_user_count")} active" + preview = "#{quarantine}#{nsfw}#{name} — #{description} (#{count})" {:ok, preview} + _ -> :error end @@ -68,52 +87,66 @@ defmodule Nola.Plugins.Link.Reddit do case HTTPoison.get("https://api.reddit.com#{path}?sr_detail=true") do {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> json = Jason.decode!(body) - op = List.first(json) - |> Map.get("data") - |> Map.get("children") - |> List.first() - |> Map.get("data") - |> IO.inspect(limit: :infinity) + + op = + List.first(json) + |> Map.get("data") + |> Map.get("children") + |> List.first() + |> Map.get("data") + |> IO.inspect(limit: :infinity) + sr = get_in(op, ["sr_detail", "display_name_prefixed"]) - {self?, url} = if Map.get(op, "selftext") == "" do - {false, Map.get(op, "url")} - else - {true, nil} - end + + {self?, url} = + if Map.get(op, "selftext") == "" do + {false, Map.get(op, "url")} + else + {true, nil} + end self_str = if(self?, do: "text", else: url) up = Map.get(op, "ups") down = Map.get(op, "downs") comments = Map.get(op, "num_comments") - nsfw = if Map.get(op, "over_18") do - "[NSFW] " - else - "" - end - state = cond do - Map.get(op, "hidden") -> "hidden" - Map.get(op, "archived") -> "archived" - Map.get(op, "locked") -> "locked" - Map.get(op, "quarantine") -> "quarantined" - Map.get(op, "removed_by") || Map.get(op, "removed_by_category") -> "removed" - Map.get(op, "banned_by") -> "banned" - Map.get(op, "pinned") -> "pinned" - Map.get(op, "stickied") -> "stickied" - true -> nil - end - flair = if flair = Map.get(op, "link_flair_text") do - "[#{flair}] " - else - "" - end + + nsfw = + if Map.get(op, "over_18") do + "[NSFW] " + else + "" + end + + state = + cond do + Map.get(op, "hidden") -> "hidden" + Map.get(op, "archived") -> "archived" + Map.get(op, "locked") -> "locked" + Map.get(op, "quarantine") -> "quarantined" + Map.get(op, "removed_by") || Map.get(op, "removed_by_category") -> "removed" + Map.get(op, "banned_by") -> "banned" + Map.get(op, "pinned") -> "pinned" + Map.get(op, "stickied") -> "stickied" + true -> nil + end + + flair = + if flair = Map.get(op, "link_flair_text") do + "[#{flair}] " + else + "" + end + title = "#{nsfw}#{sr}: #{flair}#{Map.get(op, "title")}" state_str = if(state, do: "#{state}, ") - content = "by u/#{Map.get(op, "author")} - #{state_str}#{up} up, #{comments} comments - #{self_str}" + + content = + "by u/#{Map.get(op, "author")} - #{state_str}#{up} up, #{comments} comments - #{self_str}" {:ok, [title, content]} + err -> :error end end - end diff --git a/lib/plugins/link/scraper.ex b/lib/plugins/link/scraper.ex index f5487e3..c30ae5f 100644 --- a/lib/plugins/link/scraper.ex +++ b/lib/plugins/link/scraper.ex @@ -1,5 +1,4 @@ defmodule Nola.Plugins.Link.Scraper do - defmodule UseScraper do require Logger @@ -7,28 +6,50 @@ defmodule Nola.Plugins.Link.Scraper do base_url = Keyword.get(config, :base_url, "https://api.usescraper.com") api_key = Keyword.get(config, :api_key, "unset api key") options = Keyword.get(config, :http_options, []) - headers = [{"user-agent", "nola, href@random.sh"}, - {"content-type", "application/json"}, - {"authorization", "Bearer " <> api_key}] + + headers = [ + {"user-agent", "nola, href@random.sh"}, + {"content-type", "application/json"}, + {"authorization", "Bearer " <> api_key} + ] + Logger.debug("scraper: use_scraper: get: #{url}") + with {:ok, json} <- Poison.encode(%{"url" => url, "format" => "html"}), - {:ok, %HTTPoison.Response{status_code: 200, body: body}} <- HTTPoison.post("#{base_url}/scraper/scrape", json, headers, options), - {:ok, %{"status" => "scraped", "html" => body, "meta" => meta = %{"fetchedUrlStatusCode" => 200}}} <- Poison.decode(body) do + {:ok, %HTTPoison.Response{status_code: 200, body: body}} <- + HTTPoison.post("#{base_url}/scraper/scrape", json, headers, options), + {:ok, + %{ + "status" => "scraped", + "html" => body, + "meta" => meta = %{"fetchedUrlStatusCode" => 200} + }} <- Poison.decode(body) do {:ok, body, meta} else - {:ok, %{"status" => "scraped", "text" => body, "meta" => meta = %{"fetchedUrlStatusCode" => code}}} -> + {:ok, + %{ + "status" => "scraped", + "text" => body, + "meta" => meta = %{"fetchedUrlStatusCode" => code} + }} -> Logger.error("scraper: use_scraper: scraper got http #{code} for #{url}") status = Plug.Conn.Status.reason_atom(code) {:error, status} + {:ok, %{"status" => "failed"}} -> Logger.error("scraper: use_scraper: scraper service failed for #{url}") {:error, :scrape_failed} + {:ok, %HTTPoison.Response{status_code: code, body: body}} -> Logger.error("scraper: use_scraper: scraper service failed (http #{code}) for #{url}") status = Plug.Conn.Status.reason_atom(code) {:error, status} + {:error, %HTTPoison.Error{reason: reason}} -> - Logger.error("scraper: use_scraper: scraper service failed (http #{inspect reason}) for #{url}") + Logger.error( + "scraper: use_scraper: scraper service failed (http #{inspect(reason)}) for #{url}" + ) + {:error, reason} end end @@ -36,10 +57,10 @@ defmodule Nola.Plugins.Link.Scraper do def get(url) do config = Keyword.get(Application.get_env(:nola, Nola.Plugins.Link, []), :scraper) || [] + case config[:service] do "usescraper" -> UseScraper.get(url, config[:config] || []) _ -> {:error, :scraping_disabled} end end - end diff --git a/lib/plugins/link/store.ex b/lib/plugins/link/store.ex index 566cc9a..ea43070 100644 --- a/lib/plugins/link/store.ex +++ b/lib/plugins/link/store.ex @@ -26,5 +26,4 @@ defmodule Nola.Plugins.Link.Store do [] -> nil end end - end diff --git a/lib/plugins/link/twitter.ex b/lib/plugins/link/twitter.ex index 48e6bae..ac2efe7 100644 --- a/lib/plugins/link/twitter.ex +++ b/lib/plugins/link/twitter.ex @@ -22,12 +22,15 @@ defmodule Nola.Plugins.Link.Twitter do * `expand_quoted`: Add the quoted tweet instead of its URL. Default: true. """ - def match(uri = %URI{host: twitter, path: path}, _opts) when twitter in ["twitter.com", "m.twitter.com", "mobile.twitter.com"] do + def match(uri = %URI{host: twitter, path: path}, _opts) + when twitter in ["twitter.com", "m.twitter.com", "mobile.twitter.com"] do case String.split(path, "/", parts: 4) do ["", _username, "status", status_id] -> {status_id, _} = Integer.parse(status_id) {true, %{status_id: status_id}} - _ -> false + + _ -> + false end end @@ -62,56 +65,75 @@ defmodule Nola.Plugins.Link.Twitter do # Format tweet text text = expand_twitter_text(tweet, opts) - text = if tweet.quoted_status do - quote_url = link_tweet(tweet.quoted_status, opts, true) - String.replace(text, quote_url, "") - else - text - end + + text = + if tweet.quoted_status do + quote_url = link_tweet(tweet.quoted_status, opts, true) + String.replace(text, quote_url, "") + else + text + end + text = Nola.Irc.Message.splitlong(text) - reply_to = if tweet.in_reply_to_status_id do - reply_url = link_tweet({tweet.in_reply_to_screen_name, tweet.in_reply_to_status_id}, opts) - text = if tweet.in_reply_to_screen_name == tweet.user.screen_name, do: "continued from", else: "replying to" - <<3, 15, " ↪ ", text::binary, " ", reply_url::binary, 3>> - end + reply_to = + if tweet.in_reply_to_status_id do + reply_url = link_tweet({tweet.in_reply_to_screen_name, tweet.in_reply_to_status_id}, opts) - quoted = if tweet.quoted_status do - full_text = tweet.quoted_status - |> expand_twitter_text(opts) - |> Nola.Irc.Message.splitlong_with_prefix(">") + text = + if tweet.in_reply_to_screen_name == tweet.user.screen_name, + do: "continued from", + else: "replying to" - head = format_tweet_header(tweet.quoted_status, opts, details: false, prefix: "↓ quoting") + <<3, 15, " ↪ ", text::binary, " ", reply_url::binary, 3>> + end - [head | full_text] - else - [] - end + quoted = + if tweet.quoted_status do + full_text = + tweet.quoted_status + |> expand_twitter_text(opts) + |> Nola.Irc.Message.splitlong_with_prefix(">") + + head = format_tweet_header(tweet.quoted_status, opts, details: false, prefix: "↓ quoting") + + [head | full_text] + else + [] + end - #<<2, "#{tweet.user.name} (@#{tweet.user.screen_name})", 2, " ", 3, 61, "#{foot} #{nitter_link}", 3>>, reply_to] ++ text ++ quoted + # <<2, "#{tweet.user.name} (@#{tweet.user.screen_name})", 2, " ", 3, 61, "#{foot} #{nitter_link}", 3>>, reply_to] ++ text ++ quoted + + text = + ([head, reply_to | text] ++ quoted) + |> Enum.filter(& &1) - text = [head, reply_to | text] ++ quoted - |> Enum.filter(& &1) {:ok, text} end defp expand_twitter_text(tweet, _opts) do - text = Enum.reduce(tweet.entities.urls, tweet.full_text, fn(entity, text) -> - String.replace(text, entity.url, entity.expanded_url) - end) + text = + Enum.reduce(tweet.entities.urls, tweet.full_text, fn entity, text -> + String.replace(text, entity.url, entity.expanded_url) + end) + extended = tweet.extended_entities || %{media: []} - text = Enum.reduce(extended.media, text, fn(entity, text) -> - url = Enum.filter(extended.media, fn(e) -> entity.url == e.url end) - |> Enum.map(fn(e) -> - cond do - e.type == "video" -> e.expanded_url - true -> e.media_url_https - end + + text = + Enum.reduce(extended.media, text, fn entity, text -> + url = + Enum.filter(extended.media, fn e -> entity.url == e.url end) + |> Enum.map(fn e -> + cond do + e.type == "video" -> e.expanded_url + true -> e.media_url_https + end + end) + |> Enum.join(" ") + + String.replace(text, entity.url, url) end) - |> Enum.join(" ") - String.replace(text, entity.url, url) - end) - |> HtmlEntities.decode() + |> HtmlEntities.decode() end defp format_tweet_header(tweet, opts, format_opts \\ []) do @@ -134,25 +156,28 @@ defmodule Nola.Plugins.Link.Twitter do replies = if tweet.reply_count && tweet.reply_count > 0, do: "#{tweet.reply_count} Reps" dmcad = if tweet.withheld_copyright, do: <<3, 52, "DMCA", 3>> - withheld_local = if tweet.withheld_in_countries && length(tweet.withheld_in_countries) > 0 do - "Withheld in #{length(tweet.withheld_in_countries)} countries" - end + + withheld_local = + if tweet.withheld_in_countries && length(tweet.withheld_in_countries) > 0 do + "Withheld in #{length(tweet.withheld_in_countries)} countries" + end verified = if tweet.user.verified, do: <<3, 51, "✔", 3>> - meta = if details do - [verified, nsfw, formatted_time, dmcad, withheld_local, rts, qrts, likes, replies] - else - [verified, nsfw, formatted_time, dmcad, withheld_local] - end + meta = + if details do + [verified, nsfw, formatted_time, dmcad, withheld_local, rts, qrts, likes, replies] + else + [verified, nsfw, formatted_time, dmcad, withheld_local] + end - meta = meta - |> Enum.filter(& &1) - |> Enum.join(" - ") + meta = + meta + |> Enum.filter(& &1) + |> Enum.join(" - ") meta = <<3, 15, meta::binary, " → #{link}", 3>> <<author::binary, " — ", meta::binary>> end - end diff --git a/lib/plugins/link/youtube.ex b/lib/plugins/link/youtube.ex index 0114940..adf9337 100644 --- a/lib/plugins/link/youtube.ex +++ b/lib/plugins/link/youtube.ex @@ -17,11 +17,12 @@ defmodule Nola.Plugins.Link.YouTube do """ @impl true - def match(uri = %URI{host: yt, path: "/watch", query: "v="<>video_id}, _opts) when yt in ["youtube.com", "www.youtube.com"] do + def match(uri = %URI{host: yt, path: "/watch", query: "v=" <> video_id}, _opts) + when yt in ["youtube.com", "www.youtube.com"] do {true, %{video_id: video_id}} end - def match(%URI{host: "youtu.be", path: "/"<>video_id}, _opts) do + def match(%URI{host: "youtu.be", path: "/" <> video_id}, _opts) do {true, %{video_id: video_id}} end @@ -33,40 +34,58 @@ defmodule Nola.Plugins.Link.YouTube do @impl true def expand(_uri, %{video_id: video_id}, opts) do key = Application.get_env(:nola, :youtube)[:api_key] + params = %{ "part" => "snippet,contentDetails,statistics", "id" => video_id, "key" => key } + headers = [] options = [params: params] + case HTTPoison.get("https://www.googleapis.com/youtube/v3/videos", [], options) do {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> case Jason.decode(body) do {:ok, json} -> item = List.first(json["items"]) + if item do snippet = item["snippet"] - duration = item["contentDetails"]["duration"] |> String.replace("PT", "") |> String.downcase - date = snippet["publishedAt"] - |> DateTime.from_iso8601() - |> elem(1) - |> Timex.format("{relative}", :relative) - |> elem(1) - - line = if host = Keyword.get(opts, :invidious) do - ["-> https://#{host}/watch?v=#{video_id}"] - else + + duration = + item["contentDetails"]["duration"] + |> String.replace("PT", "") + |> String.downcase() + + date = + snippet["publishedAt"] + |> DateTime.from_iso8601() + |> elem(1) + |> Timex.format("{relative}", :relative) + |> elem(1) + + line = + if host = Keyword.get(opts, :invidious) do + ["-> https://#{host}/watch?v=#{video_id}"] + else [] - end - {:ok, line ++ ["#{snippet["title"]}", "— #{duration} — uploaded by #{snippet["channelTitle"]} — #{date}" - <> " — #{item["statistics"]["viewCount"]} views, #{item["statistics"]["likeCount"]} likes"]} + end + + {:ok, + line ++ + [ + "#{snippet["title"]}", + "— #{duration} — uploaded by #{snippet["channelTitle"]} — #{date}" <> + " — #{item["statistics"]["viewCount"]} views, #{item["statistics"]["likeCount"]} likes" + ]} else :error end - _ -> :error + + _ -> + :error end end end - end |