Page MenuHomePhabricator

twitter.ex
No OneTemporary

twitter.ex

defmodule Nola.Plugins.Link.Twitter do
@behaviour Nola.Plugins.Link
@moduledoc """
# Twitter Link Preview
Configuration:
needs an API key and auth tokens:
```
config :extwitter, :oauth, [
consumer_key: "zzzzz",
consumer_secret: "xxxxxxx",
access_token: "yyyyyy",
access_token_secret: "ssshhhhhh"
]
```
options:
* `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
case String.split(path, "/", parts: 4) do
["", _username, "status", status_id] ->
{status_id, _} = Integer.parse(status_id)
{true, %{status_id: status_id}}
_ -> false
end
end
def match(_, _), do: false
@impl true
def post_match(_, _, _, _), do: false
def expand(_uri, %{status_id: status_id}, opts) do
expand_tweet(ExTwitter.show(status_id, tweet_mode: "extended"), opts)
end
defp expand_tweet(nil, _opts) do
:error
end
defp link_tweet(tweet_or_screen_id_tuple, opts, force_twitter_com \\ false)
defp link_tweet({screen_name, id}, opts, force_twitter_com) do
path = "/#{screen_name}/status/#{id}"
nitter = Keyword.get(opts, :nitter)
host = if !force_twitter_com && nitter, do: nitter, else: "twitter.com"
"https://#{host}/#{screen_name}/status/#{id}"
end
defp link_tweet(tweet, opts, force_twitter_com) do
link_tweet({tweet.user.screen_name, tweet.id}, opts, force_twitter_com)
end
defp expand_tweet(tweet, opts) do
head = format_tweet_header(tweet, opts)
# 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 = 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
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
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)
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
end)
|> Enum.join(" ")
String.replace(text, entity.url, url)
end)
|> HtmlEntities.decode()
end
defp format_tweet_header(tweet, opts, format_opts \\ []) do
prefix = Keyword.get(format_opts, :prefix, nil)
details = Keyword.get(format_opts, :details, true)
padded_prefix = if prefix, do: "#{prefix} ", else: ""
author = <<padded_prefix::binary, 2, "#{tweet.user.name} (@#{tweet.user.screen_name})", 2>>
link = link_tweet(tweet, opts)
{:ok, at} = Timex.parse(tweet.created_at, "%a %b %e %H:%M:%S %z %Y", :strftime)
{:ok, formatted_time} = Timex.format(at, "{relative}", :relative)
nsfw = if tweet.possibly_sensitive, do: <<3, 52, "NSFW", 3>>
rts = if tweet.retweet_count && tweet.retweet_count > 0, do: "#{tweet.retweet_count} RT"
likes = if tweet.favorite_count && tweet.favorite_count > 0, do: "#{tweet.favorite_count} ❤︎"
qrts = if tweet.quote_count && tweet.quote_count > 0, do: "#{tweet.quote_count} QRT"
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
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 = meta
|> Enum.filter(& &1)
|> Enum.join(" - ")
meta = <<3, 15, meta::binary, " → #{link}", 3>>
<<author::binary, " — ", meta::binary>>
end
end

File Metadata

Mime Type
text/x-ruby
Expires
Sun, Jul 6, 9:43 AM (15 h, 39 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
49817
Default Alt Text
twitter.ex (4 KB)

Event Timeline