stream_grabber 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +67 -0
- data/Rakefile +11 -0
- data/app/helpers/stream_grabber_helper.rb +14 -0
- data/lib/stream_grabber/github.rb +24 -0
- data/lib/stream_grabber/last_fm.rb +28 -0
- data/lib/stream_grabber/twitter.rb +25 -0
- data/lib/stream_grabber.rb +42 -0
- data/test/dummy_responses/github.atom +2108 -0
- data/test/dummy_responses/lastfm.xml +712 -0
- data/test/dummy_responses/twitter.json +255 -0
- data/test/github_test.rb +26 -0
- data/test/lastfm_test.rb +19 -0
- data/test/stream_grabber_test.rb +39 -0
- data/test/test_helper.rb +32 -0
- data/test/twitter_test.rb +26 -0
- metadata +176 -0
data/README.md
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
StreamGrabber
|
2
|
+
=============
|
3
|
+
|
4
|
+
StreamGrabber is a way of multiplexing streams and feeds together into a timeline, it supports twitter, last.fm and github at the moment but is designed to be fairly trivial to add new sources, providing they have some kind of public facing data stream…
|
5
|
+
|
6
|
+
Usage
|
7
|
+
-----
|
8
|
+
At the moment StreamGrabber supports Twitter, last.fm and Github so
|
9
|
+
you'll need to give it your username for these sites. Create
|
10
|
+
`#{RAILS_ROOT}/config/stream_grabber.yml` so that it looks like the
|
11
|
+
following
|
12
|
+
|
13
|
+
:twitter: username
|
14
|
+
:lastfm: username
|
15
|
+
:github: username
|
16
|
+
|
17
|
+
And then you can include the plugin in your Gemfile like so
|
18
|
+
|
19
|
+
gem 'stream_grabber'
|
20
|
+
|
21
|
+
and load the helper method in your chosen controller.
|
22
|
+
|
23
|
+
class HomepageController < ApplicationController
|
24
|
+
helper :stream_grabber
|
25
|
+
|
26
|
+
# blah blah blah
|
27
|
+
end
|
28
|
+
|
29
|
+
then in your views you use
|
30
|
+
|
31
|
+
<%= generate_stream_list %>
|
32
|
+
|
33
|
+
to render an ordered list of your most recent activity, most recent
|
34
|
+
first. There are a couple of additional options you can pass to
|
35
|
+
customise the output, the first is the number of results you'd like back
|
36
|
+
(defaults to 15) and the second is the css id and class you wish to be
|
37
|
+
applied to the output. You can use these as follows
|
38
|
+
|
39
|
+
<%= generate_stream_list 5, :class => 'foo' , :id => 'bar' %>
|
40
|
+
|
41
|
+
Adding new Sources
|
42
|
+
------------------
|
43
|
+
|
44
|
+
Sources are defined as classes in the StreamGrabber module, they are all
|
45
|
+
loaded dynamically so all your new source has to do is conform to the
|
46
|
+
following interface
|
47
|
+
|
48
|
+
module StreamGrabber
|
49
|
+
class Twitter
|
50
|
+
def initialize(user_name)
|
51
|
+
# do your setup in here to grab and parse the stream
|
52
|
+
end
|
53
|
+
|
54
|
+
def last_five
|
55
|
+
# returns your data as a timestamp keyed hash
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
And as long as `last_five` returns a hash with timestamps as keys, then
|
61
|
+
whatever is in the hash values will be squirted into the `li` elements
|
62
|
+
in the resulting list.
|
63
|
+
|
64
|
+
Over engineered? Damn Straight!!
|
65
|
+
|
66
|
+
If you want to add sources, please give me a pull request and I'll merge
|
67
|
+
them straight in.
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
module StreamGrabberHelper
|
2
|
+
def generate_stream_list(num=15, *args)
|
3
|
+
if args.present?
|
4
|
+
css_class = args.first[:class]
|
5
|
+
css_id = args.first[:id]
|
6
|
+
end
|
7
|
+
|
8
|
+
data = StreamGrabber.grab(num).inject([]){ |memo,acc| memo << content_tag(:li,raw(acc[1])) }
|
9
|
+
|
10
|
+
content_tag :ol, {:class => css_class || 'activity_list', :id => css_id || 'stream_grabber'} do
|
11
|
+
raw(data.join("\n"))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'simple-rss'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
module StreamGrabber
|
6
|
+
class Github
|
7
|
+
def initialize(user_name)
|
8
|
+
@doc = SimpleRSS.parse(open("https://github.com/#{user_name}.private.actor.atom?token=4ec7548d4e071bdc85462077a69bcdf2"))
|
9
|
+
end
|
10
|
+
|
11
|
+
def last_five
|
12
|
+
commits = {}
|
13
|
+
@doc.items.first(5).each do |item|
|
14
|
+
date = Time.parse(item[:updated].to_s).to_i
|
15
|
+
commits[date] = message_from(item[:link], item[:title])
|
16
|
+
end
|
17
|
+
commits
|
18
|
+
end
|
19
|
+
|
20
|
+
def message_from(link, title)
|
21
|
+
%Q{<a href="#{link}">#{title}</a>"}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'open-uri'
|
3
|
+
|
4
|
+
module StreamGrabber
|
5
|
+
class LastFm
|
6
|
+
def initialize(user_name)
|
7
|
+
@user_name = user_name
|
8
|
+
@doc ||= Nokogiri::XML(open("http://ws.audioscrobbler.com/2.0/?method=user.getlovedtracks&user=#{user_name}&api_key=b25b959554ed76058ac220b7b2e0a026"))
|
9
|
+
end
|
10
|
+
|
11
|
+
def last_five
|
12
|
+
tracks = {}
|
13
|
+
ff = @doc.xpath("//track").first(5)
|
14
|
+
ff.each do |elem|
|
15
|
+
date_loved = elem.>('date').first['uts'].to_i
|
16
|
+
artist_name = elem.css('artist > name').text
|
17
|
+
track_name = elem.>('name').text
|
18
|
+
url = elem.>('url').text
|
19
|
+
tracks[date_loved] = message_for(artist_name,track_name, url)
|
20
|
+
end
|
21
|
+
tracks
|
22
|
+
end
|
23
|
+
|
24
|
+
def message_for(artist, title, url)
|
25
|
+
%Q{ #{@user_name} loved the track <a href="#{url}">#{title} by #{artist}</a> on Last.fm }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'open-uri'
|
3
|
+
|
4
|
+
module StreamGrabber
|
5
|
+
class Twitter
|
6
|
+
def initialize(user_name)
|
7
|
+
@user_name = user_name
|
8
|
+
@doc = JSON.load(open("http://api.twitter.com/1/statuses/user_timeline.json?count=6&screen_name=#{user_name}"))
|
9
|
+
end
|
10
|
+
|
11
|
+
def last_five
|
12
|
+
tweets = {}
|
13
|
+
@doc.each do |tweet|
|
14
|
+
date = Time.parse(tweet["created_at"]).to_i
|
15
|
+
tweets[date] = message_from(tweet["text"], tweet["id"])
|
16
|
+
end
|
17
|
+
tweets
|
18
|
+
end
|
19
|
+
|
20
|
+
def message_from(text, id)
|
21
|
+
%Q{<a href="http://twitter.com/#{@user_name}/status/#{id}">#{text}</a>}
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'stream_grabber/last_fm'
|
2
|
+
require 'stream_grabber/github'
|
3
|
+
require 'stream_grabber/twitter'
|
4
|
+
require 'rails'
|
5
|
+
|
6
|
+
if ENV['OFFLINE']
|
7
|
+
# use test data if we are developing offline
|
8
|
+
require File.expand_path(File.join(File.dirname(__FILE__), *%w[.. test test_helper.rb]))
|
9
|
+
end
|
10
|
+
|
11
|
+
module StreamGrabber
|
12
|
+
|
13
|
+
class Engine < Rails::Engine; end
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def usernames
|
17
|
+
@usernames ||= YAML.load_file(Rails.root + 'config/stream_grabber.yml')
|
18
|
+
end
|
19
|
+
|
20
|
+
def mux_stream
|
21
|
+
messages = {}
|
22
|
+
StreamGrabber.constants.each do |klass|
|
23
|
+
k = StreamGrabber.const_get(klass)
|
24
|
+
if k.instance_of?(Class) and k.method_defined?('last_five')
|
25
|
+
name = k.name.partition('::').last.split(/(?=[A-Z])/).join("_").downcase
|
26
|
+
user_name = usernames[name.to_sym]
|
27
|
+
messages.merge!(k.new(user_name).send(:last_five))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
arr = messages.sort.reverse
|
31
|
+
end
|
32
|
+
|
33
|
+
def grab_all
|
34
|
+
mux_stream
|
35
|
+
end
|
36
|
+
|
37
|
+
def grab(n)
|
38
|
+
mux_stream.first(n)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|