Module: TwitterEmbed
- Defined in:
- lib/Parsers/TwitterEmbed.rb
Overview
Embeds a single tweet by hitting Twitter’s syndication endpoint (cdn.syndication.twitter.com/tweet-result), the same API used by Twitter’s own publish widget and by libraries like vercel/react-tweet. Returns a markdown blockquote, or ‘nil` on any fetch / parse failure so the caller can fall back to a plain link without raising.
Constant Summary collapse
- SYNDICATION_HOST =
'https://cdn.syndication.twitter.com'.freeze
Class Method Summary collapse
-
.expandEntities(tweet) ⇒ Object
Replaces shortened t.co URLs and @-mentions in the tweet body with markdown links.
- .fetch(tweetID) ⇒ Object
-
.floatToBase36(num) ⇒ Object
Ruby’s Float#to_s has no base argument, so we hand-roll the JS Number#toString(36) format (whole.fractional in base-36).
- .formatDate(value) ⇒ Object
-
.generateToken(tweetID) ⇒ Object
Token derivation matching Twitter’s publish widget / react-tweet: github.com/vercel/react-tweet/blob/main/packages/api/src/api/fetch-tweet.ts#L8 ((Number(id) / 1e15) * Math.PI).toString(36).replace(/(0+|.)/g, ”).
-
.render(tweetID, tweetURL, jekyllOpen: '') ⇒ Object
Public: fetches a tweet payload and renders it as markdown.
- .renderMarkdown(tweet, tweetURL, jekyllOpen: '') ⇒ Object
Class Method Details
.expandEntities(tweet) ⇒ Object
Replaces shortened t.co URLs and @-mentions in the tweet body with markdown links. Mirrors the original v1.1 behaviour so existing downstream renderers don’t see a behavioural change.
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/Parsers/TwitterEmbed.rb', line 84 def self.(tweet) text = (tweet['text'] || '').dup Array(tweet.dig('entities', 'urls')).each do |u| short = u['url'] next if short.nil? || short.empty? display = u['display_url'] = u['expanded_url'] || short label = display && !display.empty? ? display : text = text.gsub(short, "[#{label}](#{})") end Array(tweet.dig('entities', 'user_mentions')).each do |mention| screen = mention['screen_name'] next if screen.nil? || screen.empty? # Word-boundary-ish replace so we don't mangle substrings. text = text.gsub(/@?#{Regexp.escape(screen)}\b/) do |match| prefix = match.start_with?('@') ? '@' : '' "#{prefix}[#{screen}](https://twitter.com/#{screen})" end end text end |
.fetch(tweetID) ⇒ Object
27 28 29 30 31 32 33 34 |
# File 'lib/Parsers/TwitterEmbed.rb', line 27 def self.fetch(tweetID) url = "#{SYNDICATION_HOST}/tweet-result?id=#{tweetID}&token=#{generateToken(tweetID)}&lang=en" body = Request.body(Request.URL(url)) return nil if body.nil? || body.empty? JSON.parse(body) rescue StandardError nil end |
.floatToBase36(num) ⇒ Object
Ruby’s Float#to_s has no base argument, so we hand-roll the JS Number#toString(36) format (whole.fractional in base-36).
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/Parsers/TwitterEmbed.rb', line 45 def self.floatToBase36(num) whole = num.to_i frac = num - whole out = whole.to_s(36) return out if frac.zero? out += '.' 16.times do break if frac.zero? frac *= 36 digit = frac.to_i frac -= digit out += digit.to_s(36) end out end |
.formatDate(value) ⇒ Object
109 110 111 112 113 114 |
# File 'lib/Parsers/TwitterEmbed.rb', line 109 def self.formatDate(value) return '' if value.nil? || value.to_s.empty? Time.parse(value.to_s).strftime('%Y-%m-%d %H:%M:%S') rescue ArgumentError value.to_s end |
.generateToken(tweetID) ⇒ Object
Token derivation matching Twitter’s publish widget / react-tweet: github.com/vercel/react-tweet/blob/main/packages/api/src/api/fetch-tweet.ts#L8
((Number(id) / 1e15) * Math.PI).toString(36).replace(/(0+|\.)/g, '')
39 40 41 |
# File 'lib/Parsers/TwitterEmbed.rb', line 39 def self.generateToken(tweetID) floatToBase36((tweetID.to_f / 1e15) * Math::PI).gsub(/(0+|\.)/, '') end |
.render(tweetID, tweetURL, jekyllOpen: '') ⇒ Object
Public: fetches a tweet payload and renders it as markdown. Returns nil if the request, JSON parse, or render fails for any reason.
19 20 21 22 23 24 25 |
# File 'lib/Parsers/TwitterEmbed.rb', line 19 def self.render(tweetID, tweetURL, jekyllOpen: '') tweet = fetch(tweetID) return nil if tweet.nil? renderMarkdown(tweet, tweetURL, jekyllOpen: jekyllOpen) rescue StandardError nil end |
.renderMarkdown(tweet, tweetURL, jekyllOpen: '') ⇒ Object
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/Parsers/TwitterEmbed.rb', line 62 def self.renderMarkdown(tweet, tweetURL, jekyllOpen: '') return nil unless tweet.is_a?(Hash) text = (tweet) name = tweet.dig('user', 'name') || tweet.dig('user', 'screen_name') || 'Twitter User' screen = tweet.dig('user', 'screen_name') date = formatDate(tweet['created_at']) = screen ? "https://twitter.com/#{screen}" : tweetURL out = "\n\n" out += "■■■■■■■■■■■■■■ \n" out += "> **[#{name}](#{})#{jekyllOpen} @ Twitter Says:** \n\n" out += "> > #{text} \n\n" out += "> **Tweeted at [#{date}](#{tweetURL})#{jekyllOpen}.** \n\n" out += "■■■■■■■■■■■■■■ \n\n" out end |