romegle 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/lib/omegle.rb +333 -0
- metadata +45 -0
data/lib/omegle.rb
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
# Ruby Omegle interface. Written by Stephen Wattam, http://www.stephenwattam.com
|
|
2
|
+
# Based on the ruby-omegle gem, with major updates.
|
|
3
|
+
# Thanks to the original author, Mikhail Slyusarev
|
|
4
|
+
#
|
|
5
|
+
# Many thanks to the various protocol descriptions people did that helped with this.
|
|
6
|
+
#
|
|
7
|
+
|
|
8
|
+
# TODO:
|
|
9
|
+
# 1. Support for recaptcha, when challenged.
|
|
10
|
+
#
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
#http://code.google.com/p/omegle-api/wiki/Home#IDs_and_events
|
|
15
|
+
#https://github.com/nikkiii/omegle-api-java/blob/master/src/org/nikki/omegle/Omegle.java
|
|
16
|
+
#//Omegle events
|
|
17
|
+
# waiting, connected, gotMessage, strangerDisconnected, typing, stoppedTyping, recaptchaRequired, recaptchaRejected, count,
|
|
18
|
+
#
|
|
19
|
+
# //Spy mode events
|
|
20
|
+
# spyMessage, spyTyping, spyStoppedTyping, spyDisconnected, question, error, commonLikes,
|
|
21
|
+
#
|
|
22
|
+
# //Misc events
|
|
23
|
+
# antinudeBanned,
|
|
24
|
+
##
|
|
25
|
+
#http://code.google.com/p/saf-omegle/wiki/Events
|
|
26
|
+
|
|
27
|
+
require 'uri'
|
|
28
|
+
require 'net/http'
|
|
29
|
+
require 'json'
|
|
30
|
+
require 'thread'
|
|
31
|
+
|
|
32
|
+
##
|
|
33
|
+
# Open, manage and use a Session with Omegle.
|
|
34
|
+
#
|
|
35
|
+
# This class is capable of supporting all Omegle features, except webcam support, and constitutes a fairly thin layer over Omegle's event system.
|
|
36
|
+
#
|
|
37
|
+
# Each time the code interacts with Omegle's web services, it receives, and queues up, some events. These events may then be accessed in a thread-safe manner using the various functions of the class.
|
|
38
|
+
# These events are documented, but only loosely. They fit into rough categories:
|
|
39
|
+
#
|
|
40
|
+
# * General events: waiting, connected, gotMessage, strangerDisconnected, typing, stoppedTyping, recaptchaRequired, recaptchaRejected, count, antinudeBanned
|
|
41
|
+
# * Spy Mode Events: spyMessage, spyTyping, spyStoppedTyping, spyDisconnected, question, error, commonLikes
|
|
42
|
+
#
|
|
43
|
+
# You'll have to do some testing to verify the precise pattern you receive when doing things, as Omegle seem to change some of their events around from time to time.
|
|
44
|
+
class Omegle
|
|
45
|
+
|
|
46
|
+
##
|
|
47
|
+
# Passed to omegle in every call.
|
|
48
|
+
#
|
|
49
|
+
# By default the static headers simply set the referer.
|
|
50
|
+
STATIC_HEADERS = {"referer" => "http://omegle.com"}
|
|
51
|
+
|
|
52
|
+
##
|
|
53
|
+
# Default options. These run to:
|
|
54
|
+
# * :host --- String, the host to connect to (don't change from omegle.com unless you wish to defy their load balancer)
|
|
55
|
+
# * :question --- String, the question to ask in spy mode
|
|
56
|
+
# * :topics --- Array of Strings, the list of topics you're interested in for Omegle's topic matching
|
|
57
|
+
# * :answer --- Boolean, tell Omegle that you wish to be watched (i.e. take part in spy mode for someone else's question)
|
|
58
|
+
# * :headers --- Some HTTP headers to send with every call, handy for things like user agent spoofing.
|
|
59
|
+
#
|
|
60
|
+
# Setting :question, :topics, or :answer will set the 'mode' of the session, and will cause errors if two are
|
|
61
|
+
# set together.
|
|
62
|
+
DEFAULT_OPTIONS = {:host => 'omegle.com',
|
|
63
|
+
:question => nil,
|
|
64
|
+
:topics => nil,
|
|
65
|
+
:answer => false,
|
|
66
|
+
:headers => STATIC_HEADERS}
|
|
67
|
+
|
|
68
|
+
# The ID of this session
|
|
69
|
+
attr_accessor :id
|
|
70
|
+
|
|
71
|
+
# Construct the Omegle object and set options
|
|
72
|
+
# See #DEFAULT_OPTIONS for a list of valid options for the hash.
|
|
73
|
+
def initialize(options = {})
|
|
74
|
+
# mutex for multiple access to send/events
|
|
75
|
+
@mx = Mutex.new
|
|
76
|
+
@options = DEFAULT_OPTIONS
|
|
77
|
+
|
|
78
|
+
# Load and validate config options
|
|
79
|
+
integrate_configs(options)
|
|
80
|
+
|
|
81
|
+
# FIFO for events
|
|
82
|
+
@events = []
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# :category: Control
|
|
86
|
+
#
|
|
87
|
+
# Static construct/use method.
|
|
88
|
+
#
|
|
89
|
+
# The code below:
|
|
90
|
+
#
|
|
91
|
+
# Omegle.start(options){
|
|
92
|
+
# whatever
|
|
93
|
+
# }
|
|
94
|
+
#
|
|
95
|
+
# is equivalent to calling
|
|
96
|
+
# o = Omegle.new(options)
|
|
97
|
+
# o.start
|
|
98
|
+
# whatever
|
|
99
|
+
# o.disconnect
|
|
100
|
+
#
|
|
101
|
+
def self.start(options = {})
|
|
102
|
+
s = Omegle.new(options)
|
|
103
|
+
s.start
|
|
104
|
+
yield s
|
|
105
|
+
s.disconnect
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# :category: Control
|
|
109
|
+
#
|
|
110
|
+
# Make the initial request to omegle to start the session.
|
|
111
|
+
#
|
|
112
|
+
# This will, like all other calls to Omegle, cause some events to pile up.
|
|
113
|
+
# See #DEFAULT_OPTIONS for a list of valid options for the hash.
|
|
114
|
+
def start(options = {})
|
|
115
|
+
integrate_configs(options)
|
|
116
|
+
|
|
117
|
+
# Connect to start a session in one of three modes
|
|
118
|
+
if(@options[:question]) then
|
|
119
|
+
resp = req("start?rcs=1&firstevents=1&spid=&randid=#{get_randID}&cansavequestion=1&ask=#{URI::encode(@options[:question])}", :get)
|
|
120
|
+
elsif(@options[:answer]) then
|
|
121
|
+
resp = req("start?firstevents=1&wantsspy=1", :get) #previously ended at 6
|
|
122
|
+
else
|
|
123
|
+
topicstring = ""
|
|
124
|
+
topicstring = "&topics=#{ URI::encode(@options[:topics].to_s) }" if @options[:topics].is_a?(Array)
|
|
125
|
+
resp = req("start?firstevents=1#{topicstring}", :get) #previously ended at 6
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Was the response JSON?
|
|
129
|
+
if resp =~ /^"[\w]+:\w+"$/ then
|
|
130
|
+
# not json, simply strip quotes
|
|
131
|
+
@id = resp[1..-2]
|
|
132
|
+
else
|
|
133
|
+
#json
|
|
134
|
+
# parse, find ID, add first events
|
|
135
|
+
resp = JSON.parse(resp)
|
|
136
|
+
raise "No ID in connection response!" if not resp["clientID"]
|
|
137
|
+
@id = resp["clientID"]
|
|
138
|
+
|
|
139
|
+
# Add events if we requested it.
|
|
140
|
+
add_events(resp["events"]) if resp["events"]
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# :category: Control
|
|
145
|
+
#
|
|
146
|
+
# Check omegle to see if any events have come through.
|
|
147
|
+
def poll_events
|
|
148
|
+
ret = req('events', "id=#{@id}")
|
|
149
|
+
parse_response(ret)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# :category: Control
|
|
153
|
+
#
|
|
154
|
+
# Send a message to whoever is connected (if, indeed, they are)
|
|
155
|
+
def send(msg)
|
|
156
|
+
ret = req('send', "id=#{@id}&msg=#{URI::encode(msg)}")
|
|
157
|
+
parse_response(ret)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# :category: Control
|
|
161
|
+
#
|
|
162
|
+
# Let them know you're typing.
|
|
163
|
+
def typing
|
|
164
|
+
ret = req('typing', "id=#{@id}")
|
|
165
|
+
parse_response(ret)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# :category: Control
|
|
169
|
+
#
|
|
170
|
+
# Disconnect from Omegle.
|
|
171
|
+
#
|
|
172
|
+
# This merely requests a disconnect. Omegle will then stop issuing events,
|
|
173
|
+
# which will cause any calls to get_event to return nil, which will in turn
|
|
174
|
+
# cause listen to quit.
|
|
175
|
+
def disconnect
|
|
176
|
+
ret = req('disconnect', "id=#{@id}")
|
|
177
|
+
@id = nil if ret != nil
|
|
178
|
+
parse_response(ret)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# :category: Status
|
|
182
|
+
#
|
|
183
|
+
# Is this object in a session?
|
|
184
|
+
def connected?
|
|
185
|
+
@id != nil
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# :category: Status
|
|
189
|
+
#
|
|
190
|
+
# Is spy mode on?
|
|
191
|
+
def spy_mode?
|
|
192
|
+
@options[:question] != nil
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# :category: Status
|
|
196
|
+
#
|
|
197
|
+
# Does this session have any topics associated?
|
|
198
|
+
def topics
|
|
199
|
+
@options[:topics]
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# :category: Events
|
|
203
|
+
#
|
|
204
|
+
# Pass a code block to deal with each events as they come.
|
|
205
|
+
#
|
|
206
|
+
# This continually returns events until the omegle session is
|
|
207
|
+
# disconnected, and is the main way of interacting with the thing.
|
|
208
|
+
def listen
|
|
209
|
+
# Get any events since last call
|
|
210
|
+
poll_events
|
|
211
|
+
|
|
212
|
+
# repeatedly yield any incoming events,
|
|
213
|
+
# and keep polling.
|
|
214
|
+
#
|
|
215
|
+
# This drops out when no events are
|
|
216
|
+
# available, and automatically polls for more
|
|
217
|
+
while (e = get_event) != nil
|
|
218
|
+
yield e
|
|
219
|
+
poll_events if @events.length == 0
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# :category: Events
|
|
224
|
+
#
|
|
225
|
+
# Returns the oldest event from the FIFO
|
|
226
|
+
#
|
|
227
|
+
# This, unlike #peek_event removes the event from the list.
|
|
228
|
+
def get_event
|
|
229
|
+
@mx.synchronize{
|
|
230
|
+
return @events.pop
|
|
231
|
+
}
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
# :category: Events
|
|
235
|
+
#
|
|
236
|
+
# Returns a reference to the oldest event on the FIFO.
|
|
237
|
+
#
|
|
238
|
+
# Unlike #get_event this does not remove it from the list.
|
|
239
|
+
def peek_event
|
|
240
|
+
@mx.synchronize{
|
|
241
|
+
return @events.last
|
|
242
|
+
}
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
private
|
|
246
|
+
|
|
247
|
+
# Merges configs with the 'global config'
|
|
248
|
+
# can only work when not connected
|
|
249
|
+
def integrate_configs(options = {})
|
|
250
|
+
@mx.synchronize{
|
|
251
|
+
raise "Cannot alter session settings whilse connected." if @id != nil
|
|
252
|
+
raise "Topics cannot be specified along with a question." if options[:question] and options[:topics]
|
|
253
|
+
raise "Topics cannot be specified along with answer mode" if options[:answer] and options[:topics]
|
|
254
|
+
raise "Answer mode cannot be enabled along with a question" if options[:answer] and options[:question]
|
|
255
|
+
}
|
|
256
|
+
@options.merge!(options)
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
# Make a request to omegle. Synchronous.
|
|
261
|
+
# set args = :get to make a get request, else it's post.
|
|
262
|
+
#
|
|
263
|
+
# Returns the body if it worked, or nil if it failed.
|
|
264
|
+
#
|
|
265
|
+
# Arguments:
|
|
266
|
+
# path: The page to request, without trailing or preceeding slash (i.e. 'status' for 'omegle.com/status')
|
|
267
|
+
# args: A list of URI-formatted arguments, or the :get symbol
|
|
268
|
+
def req(path, args="")
|
|
269
|
+
omegle = Net::HTTP.start(@options[:host])
|
|
270
|
+
|
|
271
|
+
# get a return and ignore the errors that
|
|
272
|
+
# occasionally (and seemingly meaninglessly) crop up.
|
|
273
|
+
ret = nil
|
|
274
|
+
begin
|
|
275
|
+
ret = omegle.post("/#{path}", args, STATIC_HEADERS) if args != :get
|
|
276
|
+
ret = omegle.get("/#{path}", STATIC_HEADERS) if args == :get
|
|
277
|
+
rescue EOFError
|
|
278
|
+
rescue TimeoutError
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# return nil or the content if the call worked
|
|
282
|
+
return ret.body if ret and ret.code == "200"
|
|
283
|
+
return nil
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
# Add an event to the FIFO in-order
|
|
287
|
+
def add_events(evts)
|
|
288
|
+
# Accept one event or many
|
|
289
|
+
evts = [evts] if not evts.is_a? Array
|
|
290
|
+
|
|
291
|
+
@mx.synchronize{
|
|
292
|
+
# add to front of array, pop off back
|
|
293
|
+
evts.each{|e|
|
|
294
|
+
@events = [e] + @events
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
# Returns an 8-character random ID used when connecting.
|
|
300
|
+
# This seems to have no bearing on functionality, but
|
|
301
|
+
# might come in handy, possibly.
|
|
302
|
+
def get_randID()
|
|
303
|
+
# The JS in the omegle page says:
|
|
304
|
+
# if(!randID||8!==randID.length)
|
|
305
|
+
# randID=function(){
|
|
306
|
+
# for(var a="",b=0;8>b;b++)
|
|
307
|
+
# var c=Math.floor(32*Math.random()),
|
|
308
|
+
# a=a+"23456789ABCDEFGHJKLMNPQRSTUVWXYZ".charAt(c);
|
|
309
|
+
# return a
|
|
310
|
+
# }();
|
|
311
|
+
str = "";
|
|
312
|
+
8.times{ str += "23456789ABCDEFGHJKLMNPQRSTUVWXYZ"[ (rand() * 32).to_i ] }
|
|
313
|
+
|
|
314
|
+
return str;
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
# Parse a JSON response from omegle,
|
|
318
|
+
# and add its events to the FIFO
|
|
319
|
+
def parse_response(str)
|
|
320
|
+
# win or null don't contain any events, so skip.
|
|
321
|
+
return if str == nil or (%w{win null}.include?(str.to_s.strip))
|
|
322
|
+
|
|
323
|
+
# try to parse
|
|
324
|
+
evts = JSON.parse(str)
|
|
325
|
+
|
|
326
|
+
# check it's events
|
|
327
|
+
return if not evts.is_a? Array
|
|
328
|
+
|
|
329
|
+
# add in order
|
|
330
|
+
add_events(evts)
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: romegle
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Stephen Wattam
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2013-02-05 00:00:00.000000000 Z
|
|
13
|
+
dependencies: []
|
|
14
|
+
description: A simple hello world gem
|
|
15
|
+
email: stephenwattam@gmail.com
|
|
16
|
+
executables: []
|
|
17
|
+
extensions: []
|
|
18
|
+
extra_rdoc_files: []
|
|
19
|
+
files:
|
|
20
|
+
- lib/omegle.rb
|
|
21
|
+
homepage: http://stephenwattam.com/projects/romegle
|
|
22
|
+
licenses: []
|
|
23
|
+
post_install_message:
|
|
24
|
+
rdoc_options: []
|
|
25
|
+
require_paths:
|
|
26
|
+
- lib
|
|
27
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
28
|
+
none: false
|
|
29
|
+
requirements:
|
|
30
|
+
- - ! '>='
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '0'
|
|
33
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
34
|
+
none: false
|
|
35
|
+
requirements:
|
|
36
|
+
- - ! '>='
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: '0'
|
|
39
|
+
requirements: []
|
|
40
|
+
rubyforge_project:
|
|
41
|
+
rubygems_version: 1.8.23
|
|
42
|
+
signing_key:
|
|
43
|
+
specification_version: 3
|
|
44
|
+
summary: A pure ruby interface to Omegle.com
|
|
45
|
+
test_files: []
|