Skip to content

Commit

Permalink
Complete
Browse files Browse the repository at this point in the history
  • Loading branch information
yayugu committed Mar 2, 2014
1 parent fb5f054 commit cf4fb8e
Show file tree
Hide file tree
Showing 16 changed files with 314 additions and 8 deletions.
11 changes: 10 additions & 1 deletion app/controllers/auth_controller.rb
Expand Up @@ -34,7 +34,16 @@ def callback
)
end

#bookmarklet = URI.encode "javascript:void(function(){location.href = '#{base_url}/#{@id}' + location.pathname;})();"
if @user
session[:user_id] = @user.id
end

redirect_to root_url
end

def logout
reset_session
redirect_to root_url
end

private
Expand Down
37 changes: 37 additions & 0 deletions app/controllers/feed_controller.rb
@@ -1,10 +1,47 @@
class FeedController < ApplicationController
TWEET_COUNT = 200

before_action :prepare_twitter_client

def user
res = @client.user(params[:name], TWEET_COUNT)
@image_url = res.first['user']['profile_image_url']
@name = res.first['user']['screen_name']
@tweets = Tweet.tweets_from_hash_list(res)
render_rss
end

def list
res = @client.list(params[:name], params[:slug], TWEET_COUNT)
@name = params[:name]
@slug = params[:slug]
@tweets = Tweet.tweets_from_hash_list(res)
render_rss
end

def search
res = @client.search(params[:q], TWEET_COUNT)
@query = params[:q]
@tweets = Tweet.tweets_from_hash_list(res)
render_rss
end

private

def user_for_api_token
url_id_hash = params[:url_id_hash]
url_id_hash && (@user = User.where(url_id_hash: url_id_hash).first)
end

def prepare_twitter_client
user = user_for_api_token
unless user
render :file => "public/404.html", :status => :unauthorized
end
@client = TwitterClient.new(user.twitter_access_token, user.twitter_access_secret)
end

def render_rss
render layout: false, content_type: 'application/rss+xml'
end
end
14 changes: 14 additions & 0 deletions app/controllers/main_controller.rb
@@ -0,0 +1,14 @@
class MainController < ApplicationController
before_action :set_user

def index
end

private

def set_user
if session[:user_id]
@user = User.find(session[:user_id])
end
end
end
10 changes: 10 additions & 0 deletions app/helpers/application_helper.rb
@@ -1,2 +1,12 @@
module ApplicationHelper
def bookmarklet_escape(js)
# output_safety string to raw string
String.new(js)
.gsub(/^\s+/, '')
.gsub(/\s+$/, '')
.gsub("\n", '')
.gsub('%', '%25')
.gsub(" ", '%20')
.gsub('"', '%22')
end
end
36 changes: 36 additions & 0 deletions app/models/tweet.rb
@@ -0,0 +1,36 @@
class Tweet
class << self
def tweets_from_hash_list(hash_list)
hash_list.map{|tweet_hash| Tweet.new(tweet_hash) }
end
end

def initialize(tweet_hash)
@hash = tweet_hash
Rails.logger.debug @hash
end

def markupped_text
MarkupTweet::markup_tweet(@hash)
end

def screen_name
@hash['user']['screen_name']
end

def url
"https://twitter.com/#{screen_name}/status/#{@hash['id']}"
end

def description
" <img src='#{@hash['user']['profile_image_url']}' width='16px' height='16px' /> #{markupped_text} "
end

def created_at
@hash['created_at']
end

def author
@hash['source'].gsub(/<\/?[^>]*>/, "")
end
end
19 changes: 19 additions & 0 deletions app/views/feed/_rss.slim
@@ -0,0 +1,19 @@
doctype xml
rss[version='2.0'
xmlns:content='http://purl.org/rss/1.0/modules/content/']
channel
title= @title
link= @link
description= ' '
- if @image_url
image
url= @image_url
title= @image_title
link= @link
- @tweets.each do |tweet|
item
title= tweet.screen_name
link= tweet.url
description= tweet.description
author= tweet.author
pubDate= tweet.created_at
4 changes: 4 additions & 0 deletions app/views/feed/list.erb
@@ -0,0 +1,4 @@
<%
@title = "#{@slug} / #{@name} / Twitter"
@link = "http://twitter.com/#{@name}/#{@slug}"
%><%= render partial: "rss" %>
5 changes: 5 additions & 0 deletions app/views/feed/search.erb
@@ -0,0 +1,5 @@
<%
require 'uri'
@title = "#{@query} / search / Twitter"
@link = "http://twitter.com/search?q=#{URI::encode_www_form_component(@query)}"
%><%= render partial: "rss" %>
5 changes: 5 additions & 0 deletions app/views/feed/user.erb
@@ -0,0 +1,5 @@
<%
@title = "#{@name} / Twitter"
@link = "http://twitter.com/#{@name}"
@image_title = "#{@name}'s icon"
%><%= render partial: "rss" %>
50 changes: 50 additions & 0 deletions app/views/main/_bookmarklet.js.erb
@@ -0,0 +1,50 @@
javascript:void(function(){
<%# http://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript %>
<%# without decode escape %>
var parameterByName = function (query, name) {
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
results = regex.exec(query);
return results == null ? "" : results[1];
};
var rssUrl = function (path, query, root_url, url_id_hash) {
var search_pattern = /search\/?$/;
var list_pattern = /([a-zA-Z0-9_]+)\/lists\/([a-zA-Z0-9_]+)/;
var user_pattern = /([a-zA-Z0-9_]+)/;
var m;
if (m = path.match(search_pattern)) {
return root_url +
'feed/search?q=' +
parameterByName(query, 'q') +
'&url_id_hash=' +
url_id_hash;
}
if (m = path.match(list_pattern)) {
return root_url +
'feed/list?name=' +
m[0] +
'&slug=' +
m[1] +
'&url_id_hash=' +
url_id_hash;
}
if (m = path.match(user_pattern)) {
return root_url +
'feed/user?name=' +
m[0] +
'&url_id_hash=' +
url_id_hash;
}
return null;
};
var url = rssUrl(
location.pathname,
location.search,
"<%= root_url %>",
"<%= @user.url_id_hash %>"
);
if (!rssUrl) {
alert('Twitter Good RSS error: generate URL failed.');
}
location.href = url;
})();
30 changes: 30 additions & 0 deletions app/views/main/index.html.slim
@@ -0,0 +1,30 @@
h1 Twitter Great RSS
div

- if @user
div You can generate RSS with URL like:
ul
li #{root_url}feed/user?user=USERNAME&url_id_hash=#{@user.url_id_hash}
li #{root_url}feed/list?user=USERNAME&slug=LISTNAME&url_id_hash=#{@user.url_id_hash}
li #{root_url}feed/search?q=KEYWORD&url_id_hash=#{@user.url_id_hash}
div
| Bookmarklet is also available. →
a href=bookmarklet_escape(render(partial: 'bookmarklet', formats: ['js']))
| Bookmark this Bookmarklet
br
div
== link_to "Logout", controller: "auth", action: "logout"

- else
div
== link_to "Sign in with twitter", controller: "auth", action: "auth"
div Generate RSS for:
ul
li user tweets
li list tweets
li search result tweets

br
div
| Code is available on
a href="http://github.com/yayugu/twitter-great-rss" GitHub
1 change: 1 addition & 0 deletions config/application.rb
Expand Up @@ -19,5 +19,6 @@ class Application < Rails::Application
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
# config.i18n.default_locale = :de
config.autoload_paths += %W(#{config.root}/lib)
end
end
1 change: 1 addition & 0 deletions config/routes.rb
Expand Up @@ -4,6 +4,7 @@
scope :auth do
get 'auth' => 'auth#auth'
get 'callback' => 'auth#callback'
get 'logout' => 'auth#logout'
end

scope :feed do
Expand Down
46 changes: 46 additions & 0 deletions lib/markup_tweet.rb
@@ -0,0 +1,46 @@
class MarkupTweet
class << self
def markup_tweet(tweet)
text = tweet['text']
entities = tweet['entities']
MarkupTweet::markup_media(text, entities)
MarkupTweet::markup_urls(text, entities)
MarkupTweet::markup_user_mentions(text, entities)
MarkupTweet::markup_hashtags(text, entities)
text
end

# see https://dev.twitter.com/docs/tweet-entities
def markup_media(text, entities)
return text unless entities['media']
entities['media'].each do |image|
text << "<div><a href='#{image['display_url']}'><img src='#{image['media_url']}' /></a></div>"
end
text
end

def markup_urls(text, entities)
entities['urls'].each do |url|
new_url = url['expanded_url'] || url['url']
text.gsub!(url['url'], "<a href='#{new_url}'>#{new_url}</a>")
end
text
end

def markup_user_mentions(text, entities)
entities['user_mentions'].each do |mention|
screen_name = mention['screen_name']
text.gsub!("@#{screen_name}", "<a href='http://twitter.com/#{screen_name}'>@#{screen_name}</a>")
end
text
end

def markup_hashtags(text, entities)
entities['hashtags'].each do |hashtag|
hashtag_text = hashtag['text']
text.gsub!(/[\##♯]#{Regexp.quote hashtag_text}/, "<a href='http://twitter.com/search?q=%23#{hashtag_text}'>##{hashtag_text}</a>")
end
text
end
end
end
7 changes: 0 additions & 7 deletions lib/oauth_twitter.rb
Expand Up @@ -17,13 +17,6 @@ def access_token(request_token, request_token_secret, oauth_token, oauth_verifie
)
end

def get_and_json_parse(url, account)
body = OAuth::AccessToken.new(self.consumer, account.access_token, account.access_secret)
.get(url)
.body
JSON.parse(body)
end

def consumer
OAuth::Consumer.new(
ENV['CONSUMER_KEY'],
Expand Down
46 changes: 46 additions & 0 deletions lib/twitter_client.rb
@@ -0,0 +1,46 @@
require 'oauth'
require 'oauth_twitter'
require 'uri'

class TwitterClient
def initialize(access_token, access_secret)
@access_token = OAuth::AccessToken.new(OAuthTwitter.new.consumer, access_token, access_secret)
end

def user(name, count)
get_and_json_parse(user_sub_url(name, count))
end

def list(name, slug, count)
get_and_json_parse(list_sub_url(name, slug, count))
end

def search(query, count)
get_and_json_parse(search_sub_url(query, count))['statuses']
end

private

def user_sub_url(name, count)
"/statuses/user_timeline.json?screen_name=#{name}&include_entities=true&count=#{count}&include_rts=true"
end

def list_sub_url(name, slug, count)
"/lists/statuses.json?slug=#{slug}&owner_screen_name=#{name}&include_entities=true&count=#{count}&include_rts=true"
end

def search_sub_url(query, count)
"/search/tweets.json?q=#{URI::encode_www_form_component(query)}&include_entities=true&count=#{count}"
end

def get_and_json_parse(sub_url)
body = @access_token
.get(api_url(sub_url))
.body
JSON.parse(body)
end

def api_url(sub_url)
"#{OAuthTwitter::SITE_URL}/1.1/#{sub_url}"
end
end

0 comments on commit cf4fb8e

Please sign in to comment.