turntable_api 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2 @@
1
+ require "turntable_api/version"
2
+ require "turntable_api/bot"
@@ -0,0 +1,162 @@
1
+ require 'rubygems'
2
+ require 'websocker'
3
+ require 'json'
4
+ require 'digest/sha1'
5
+ require 'httparty'
6
+
7
+ module TurntableAPI
8
+ class Bot
9
+ attr_reader :connected, :roomid
10
+
11
+ def initialize(opts = {})
12
+ @userid = opts[:userid]
13
+ @clientid = opts[:clientid] || "#{Time.now.to_i}-#{rand}"
14
+ @auth = opts[:auth]
15
+ @logger = opts[:logger] || Logger.new(STDOUT)
16
+ @msgId = 0
17
+ @command_handlers ||= {}
18
+ @response_handler ||= {}
19
+ @received_heartbeat = false
20
+ end
21
+
22
+ def start
23
+ connect
24
+ end
25
+
26
+ def room_register(roomid)
27
+ @ws.close unless @ws.nil?
28
+ if roomid.instance_of?(Hash) then roomid = roomid[:roomid] end
29
+ connect(roomid)
30
+ call_api 'room.register', :roomid => roomid
31
+ @roomid = roomid
32
+ end
33
+
34
+ def room_vote(opts)
35
+ dir = opts[:val]
36
+ songid = opts[:songid]
37
+ raise ArgumentError, "dir and songid are required" if songid.nil? or dir.nil?
38
+ opts[:vh] ||= hash("#{@roomid}#{dir}#{songid}")
39
+ opts[:th] ||= hash(rand.to_s)
40
+ opts[:ph] ||= hash(rand.to_s)
41
+ send_command('room_vote', opts)
42
+ end
43
+ alias_method :vote, :room_vote
44
+
45
+ # sends a command and sets up a callback that triggers
46
+ # when the reply is received
47
+ def on_response(cmd, opts={}, &blk)
48
+ msg_id = send_command cmd, opts
49
+ @response_handler[msg_id] = blk
50
+ end
51
+
52
+ def method_missing(meth, *args)
53
+ @logger.debug "method_missing #{meth}: #{args}"
54
+ hash = args[0] unless args.empty?
55
+ hash ||= {}
56
+ send_command(meth, hash)
57
+ end
58
+
59
+ # send a command to Turntable.FM
60
+ def send_command(command, opts={})
61
+ command = command.to_s.sub('_', '.')
62
+ call_api(command, opts)
63
+ end
64
+
65
+ # triggered when we receive a command from Turntable.FM
66
+ def on_command(command, &blk)
67
+ @command_handlers[command.to_sym] = blk
68
+ end
69
+
70
+ def on_ready(&blk)
71
+ @ready_handler = blk
72
+ end
73
+
74
+ def on_error(&blk)
75
+ @error_handler = blk
76
+ end
77
+
78
+ def on_message(msg)
79
+ if msg == "~m~10~m~no_session"
80
+ authenticate
81
+ elsif msg =~ /~m~[0-9]+~m~(~h~[0-9]+)/
82
+ hb = $1
83
+ @ready_handler.call unless @received_heartbeat or @ready_handler.nil?
84
+ @received_heartbeat = true
85
+ send_text(hb)
86
+ else
87
+ msg =~ /~m~\d*~m~(\{.*\})/
88
+ json = JSON.parse($1)
89
+ command = json["command"]
90
+ err = json["err"]
91
+ msgid = json["msgid"]
92
+ @error_handler.call(err) unless @error_handler.nil? or err.nil?
93
+ unless command.nil?
94
+ blk = @command_handlers[command.to_sym]
95
+ blk.call(json) unless blk.nil?
96
+ end
97
+ unless @response_handler[msgid].nil?()
98
+ blk = @response_handler[msgid]
99
+ blk.call(json) unless blk.nil?
100
+ @response_handler.delete(msgid)
101
+ end
102
+ end
103
+ end
104
+
105
+ private
106
+
107
+ def connect(roomid='unknown')
108
+ @ws = Websocker::Client.new(:host => chatserver(roomid), :path => "/socket.io/websocket")
109
+ @ws.connect
110
+ @ws.on_message do |msg|
111
+ on_message msg
112
+ end
113
+ @ws.on_closed do
114
+ on_closed
115
+ end
116
+ @listener_thread = @ws.listen
117
+ @connected = true
118
+ end
119
+
120
+ def on_closed
121
+ @connected = false
122
+ Thread.kill(@listener_thread) unless @listener_thread.nil?
123
+ end
124
+
125
+ def authenticate
126
+ call_api "user.authenticate"
127
+ end
128
+
129
+ def call_api(api, addl_params={})
130
+ messageId = next_message_id
131
+ params = { 'api' => api, 'userid' => @userid, 'clientid' => @clientid, 'userauth' => @auth, 'msgid' => messageId }
132
+ params['roomid'] = @roomid if @roomid
133
+ params.merge!(addl_params)
134
+ send_text(params.to_json)
135
+ return messageId
136
+ end
137
+
138
+ def send_text(txt)
139
+ msg = "~m~#{txt.length}~m~#{txt}"
140
+ send_raw(msg)
141
+ end
142
+
143
+ def send_raw(msg)
144
+ @logger.debug "Sent: #{msg}"
145
+ @ws.send(msg)
146
+ end
147
+
148
+ def next_message_id
149
+ @msgId += 1
150
+ end
151
+
152
+ def hash(msg)
153
+ Digest::SHA1.hexdigest(msg)
154
+ end
155
+
156
+ def chatserver(roomid)
157
+ resp = HTTParty.get("http://turntable.fm/api/room.which_chatserver?roomid=#{roomid}").body
158
+ JSON.parse(resp)[1]["chatserver"][0]
159
+ end
160
+ end
161
+
162
+ end
@@ -0,0 +1,3 @@
1
+ module TurntableAPI
2
+ VERSION = "0.0.2"
3
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: turntable_api
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Lawrence Mcalpin
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-06-11 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: websocker
16
+ requirement: &24047748 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *24047748
25
+ - !ruby/object:Gem::Dependency
26
+ name: json
27
+ requirement: &24046992 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *24046992
36
+ - !ruby/object:Gem::Dependency
37
+ name: httparty
38
+ requirement: &24046212 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *24046212
47
+ - !ruby/object:Gem::Dependency
48
+ name: rspec
49
+ requirement: &24060960 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *24060960
58
+ - !ruby/object:Gem::Dependency
59
+ name: rake
60
+ requirement: &24059892 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *24059892
69
+ description: A simple API for making Turntable.fm bots.
70
+ email:
71
+ - lmcalpin+turntable_api@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - lib/turntable_api/bot.rb
77
+ - lib/turntable_api/version.rb
78
+ - lib/turntable_api.rb
79
+ homepage: ''
80
+ licenses: []
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ none: false
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements: []
98
+ rubyforge_project: turntable_api
99
+ rubygems_version: 1.8.16
100
+ signing_key:
101
+ specification_version: 3
102
+ summary: API for creating Turntable bots.
103
+ test_files: []