nezetic-ruby-xbmc 0.1.1
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 +26 -0
- data/lib/ruby-xbmc.rb +576 -0
- metadata +63 -0
data/README
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
ruby-xbmc
|
2
|
+
a remote access library for XBMC
|
3
|
+
=============================
|
4
|
+
|
5
|
+
ruby-xbmc is a ruby wrapper for the XBMC Web Server HTTP API.
|
6
|
+
|
7
|
+
It provides a remote access to any XBMC running on the local network,
|
8
|
+
in a simple way (methods follow the ones from XBMC API).
|
9
|
+
|
10
|
+
Example:
|
11
|
+
|
12
|
+
irb(main):001:0> require 'ruby-xbmc'
|
13
|
+
irb(main):002:0> xbmc = XBMC::XBMC.new(hostname, port, user, pass)
|
14
|
+
=> #<XBMC::XBMC:0x1128e7c>
|
15
|
+
|
16
|
+
irb(main):003:0> pp xbmc.GetMediaLocation("music")
|
17
|
+
[{"name"=>"Jazz", "type"=>"1", "path"=>"/mnt/data/Music/Jazz/"},
|
18
|
+
{"name"=>"Electro", "type"=>"1", "path"=>"/mnt/data/Music/Electro/"},
|
19
|
+
{"name"=>"Metal", "type"=>"1", "path"=>"/mnt/data/Music/Metal/"},
|
20
|
+
{"name"=>"Last.fm", "type"=>"1", "path"=>"lastfm://"}]
|
21
|
+
|
22
|
+
References
|
23
|
+
=========
|
24
|
+
|
25
|
+
http://xbmc.org/wiki/?title=Web_Server_HTTP_API
|
26
|
+
|
data/lib/ruby-xbmc.rb
ADDED
@@ -0,0 +1,576 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
=begin
|
4
|
+
ruby-xbmc
|
5
|
+
|
6
|
+
ruby-xbmc is a ruby wrapper for the XBMC Web Server HTTP API.
|
7
|
+
|
8
|
+
It provides a remote access to any XBMC running on the local network,
|
9
|
+
in a simple way (methods follow the ones from XBMC API).
|
10
|
+
|
11
|
+
|
12
|
+
Example:
|
13
|
+
|
14
|
+
irb(main):001:0> xbmc = XBMC::XBMC.new(hostname, port, user, pass)
|
15
|
+
=> #<XBMC::XBMC:0x1128e7c>
|
16
|
+
|
17
|
+
irb(main):002:0> pp xbmc.GetMediaLocation("music")
|
18
|
+
[{"name"=>"Jazz", "type"=>"1", "path"=>"/mnt/data/Music/Jazz/"},
|
19
|
+
{"name"=>"Electro", "type"=>"1", "path"=>"/mnt/data/Music/Electro/"},
|
20
|
+
{"name"=>"Metal", "type"=>"1", "path"=>"/mnt/data/Music/Metal/"},
|
21
|
+
{"name"=>"Last.fm", "type"=>"1", "path"=>"lastfm://"}]
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
Copyright (C) 2009 Cedric TESSIER
|
26
|
+
|
27
|
+
Contact: nezetic.info
|
28
|
+
|
29
|
+
This program is free software: you can redistribute it and/or modify
|
30
|
+
it under the terms of the GNU General Public License as published by
|
31
|
+
the Free Software Foundation, either version 3 of the License, or
|
32
|
+
(at your option) any later version.
|
33
|
+
|
34
|
+
This program is distributed in the hope that it will be useful,
|
35
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
36
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
37
|
+
GNU General Public License for more details.
|
38
|
+
|
39
|
+
You should have received a copy of the GNU General Public License
|
40
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
41
|
+
=end
|
42
|
+
|
43
|
+
begin
|
44
|
+
require 'rubygems'
|
45
|
+
rescue LoadError
|
46
|
+
end
|
47
|
+
|
48
|
+
require 'iconv'
|
49
|
+
require 'uri'
|
50
|
+
require 'open-uri'
|
51
|
+
require 'hpricot'
|
52
|
+
|
53
|
+
class Object
|
54
|
+
def caller_method
|
55
|
+
caller[1] =~ /`([^']*)'/ and $1
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class Array
|
60
|
+
def to_hash(keys)
|
61
|
+
return nil if(keys.length != self.length)
|
62
|
+
Hash[*keys.zip(self).flatten]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class String
|
67
|
+
def transliterate
|
68
|
+
Iconv.iconv('ASCII//IGNORE//TRANSLIT', 'UTF-8', self).to_s
|
69
|
+
rescue
|
70
|
+
self
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Module for the library
|
75
|
+
#
|
76
|
+
#=Usage example
|
77
|
+
# First, we need to create the link between us and XBMC:
|
78
|
+
#
|
79
|
+
# xbmc = XBMC::XBMC.new(hostname, port, user, pass)
|
80
|
+
#
|
81
|
+
# then, we can do a lot of things, following XBMC API.
|
82
|
+
#
|
83
|
+
#==Set current XBMC Volume
|
84
|
+
# xbmc.SetVolume(95)
|
85
|
+
#==Get currently playing file data
|
86
|
+
# xbmc.GetCurrentlyPlaying
|
87
|
+
#==Get a files list from music library, with insertion dates
|
88
|
+
# xbmc.GetMediaLocation("music", "/mnt/data/Music/Jazz/", true)
|
89
|
+
#==Retrieve playlist contents
|
90
|
+
# xbmc.GetPlaylistContents
|
91
|
+
#==Get some system information
|
92
|
+
# xbmc.GetSystemInfoByName("weather.location","weather.temperature")
|
93
|
+
#
|
94
|
+
module XBMC
|
95
|
+
#User Agent Name
|
96
|
+
NAME = 'Ruby/XBMC'
|
97
|
+
#Library Version
|
98
|
+
VERSION = '0.1'
|
99
|
+
#Complete User-Agent
|
100
|
+
USER_AGENT = "%s %s" % [NAME, VERSION]
|
101
|
+
# scheme used in HTTP transfers (http/https)
|
102
|
+
SCHEME = "http"
|
103
|
+
# XBMC Command API
|
104
|
+
CMDPATH = "/xbmcCmds/xbmcHttp?command="
|
105
|
+
|
106
|
+
MUSIC_PLAYLIST = 0
|
107
|
+
VIDEO_PLAYLIST = 1
|
108
|
+
|
109
|
+
TYPE_DIRECTORY = 1
|
110
|
+
TYPE_FILE = 0
|
111
|
+
|
112
|
+
#Error class when not authenticated
|
113
|
+
class XBMC::UnauthenticatedError < StandardError
|
114
|
+
def initialize(m=nil)
|
115
|
+
super(m.nil? ? "You are not connected (no user/password)": m)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
#Error class when password and user mismatched
|
120
|
+
class XBMC::WrongCredentialsError < XBMC::UnauthenticatedError
|
121
|
+
def initialize()
|
122
|
+
super("User / password mismatched")
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
#Connection class used to specify credentials and proxy settings
|
127
|
+
class Connection
|
128
|
+
#network hostname
|
129
|
+
attr_accessor :host
|
130
|
+
#network port
|
131
|
+
attr_accessor :port
|
132
|
+
#username
|
133
|
+
attr_accessor :user
|
134
|
+
#password
|
135
|
+
attr_accessor :password
|
136
|
+
|
137
|
+
#proxy url eg. http://user:pass@proxy:8080
|
138
|
+
attr_writer :proxy
|
139
|
+
|
140
|
+
def initialize(host, port=nil, user=nil, pass=nil)
|
141
|
+
@host=host
|
142
|
+
@port=port
|
143
|
+
@user=user
|
144
|
+
@password=pass
|
145
|
+
end
|
146
|
+
|
147
|
+
#proxy getter
|
148
|
+
def proxy
|
149
|
+
return @proxy unless @proxy.nil?
|
150
|
+
ENV["proxy"]
|
151
|
+
end
|
152
|
+
|
153
|
+
def exec(command) #:nodoc:
|
154
|
+
command.rstrip!
|
155
|
+
command += "()" if command[-1,1] != ")"
|
156
|
+
url = SCHEME + "://" + host + ":" + port + CMDPATH + command
|
157
|
+
|
158
|
+
begin
|
159
|
+
return open(url,"r",http_opts)
|
160
|
+
rescue OpenURI::HTTPError => e
|
161
|
+
if e.io.status.first.to_i == 401
|
162
|
+
raise (user.nil? ? UnauthenticatedError.new : WrongCredentialsError.new )
|
163
|
+
end
|
164
|
+
raise e
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
protected
|
169
|
+
def http_opts #:nodoc:
|
170
|
+
ret={}
|
171
|
+
ret[:http_basic_authentication]=[user,password] unless user.nil?
|
172
|
+
ret[:proxy]=proxy
|
173
|
+
ret["User-Agent"]=USER_AGENT
|
174
|
+
return ret
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
class XBMC
|
180
|
+
attr_accessor :error
|
181
|
+
|
182
|
+
##### XBMC API
|
183
|
+
# Commands that Retrieve Information
|
184
|
+
def GetMediaLocation(type, path=nil, showdate=false)
|
185
|
+
if(showdate)
|
186
|
+
parse_asdictlist(cmd(with_args(type, path, "showdate")), ["name", "path", "type", "date"])
|
187
|
+
else
|
188
|
+
parse_asdictlist(cmd(with_args(type, path)), ["name", "path", "type"])
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def GetShares(type)
|
193
|
+
parse_asdictlist(cmd(with_args(type)), ["name", "path"])
|
194
|
+
end
|
195
|
+
|
196
|
+
def GetCurrentPlaylist
|
197
|
+
parse(cmd())
|
198
|
+
end
|
199
|
+
|
200
|
+
def GetCurrentlyPlaying
|
201
|
+
song = parse_asdict(cmd())
|
202
|
+
return nil if(song.length <= 1)
|
203
|
+
song
|
204
|
+
end
|
205
|
+
|
206
|
+
def GetCurrentSlide
|
207
|
+
parse(cmd())
|
208
|
+
end
|
209
|
+
|
210
|
+
def GetDirectory(directory, mask=" ", showdate=false)
|
211
|
+
if(showdate)
|
212
|
+
parse_asdictlist(cmd(with_args(directory, mask, 1)), ["path", "date"])
|
213
|
+
else
|
214
|
+
parse_aslist(cmd(with_args(directory, mask)))
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def GetGuiDescription
|
219
|
+
parse_asdict(cmd())
|
220
|
+
end
|
221
|
+
|
222
|
+
def GetGuiSetting(type, name)
|
223
|
+
parse(cmd(with_args(type, name)))
|
224
|
+
end
|
225
|
+
|
226
|
+
def GetGuiStatus
|
227
|
+
parse_asdict(cmd())
|
228
|
+
end
|
229
|
+
|
230
|
+
def GetMovieDetails
|
231
|
+
puts "Not implemented"
|
232
|
+
end
|
233
|
+
|
234
|
+
def GetPercentage
|
235
|
+
parse(cmd())
|
236
|
+
end
|
237
|
+
|
238
|
+
def GetPlaylistContents(playlist=nil)
|
239
|
+
parse_aslist(cmd(with_args(playlist)))
|
240
|
+
end
|
241
|
+
|
242
|
+
def GetPlaylistLength(playlist=nil)
|
243
|
+
parse(cmd(with_args(playlist)))
|
244
|
+
end
|
245
|
+
|
246
|
+
def GetPlaylistSong(position=nil)
|
247
|
+
parse(cmd(with_args(position)))
|
248
|
+
end
|
249
|
+
|
250
|
+
def GetPlaySpeed
|
251
|
+
parse(cmd())
|
252
|
+
end
|
253
|
+
|
254
|
+
def GetMusicLabel
|
255
|
+
puts "Not implemented"
|
256
|
+
end
|
257
|
+
|
258
|
+
def GetRecordStatus
|
259
|
+
puts "Not implemented"
|
260
|
+
end
|
261
|
+
|
262
|
+
def GetVideoLabel
|
263
|
+
puts "Not implemented"
|
264
|
+
end
|
265
|
+
|
266
|
+
def GetSlideshowContents
|
267
|
+
parse_aslist(cmd())
|
268
|
+
end
|
269
|
+
|
270
|
+
def GetSystemInfo(*args)
|
271
|
+
parse_aslist(cmd(with_args(args)))
|
272
|
+
end
|
273
|
+
|
274
|
+
def GetSystemInfoByName(*args)
|
275
|
+
parse_aslist(cmd(with_args(args)))
|
276
|
+
end
|
277
|
+
|
278
|
+
def GetTagFromFilename(fullpath)
|
279
|
+
parse_asdict(cmd(with_args(fullpath)))
|
280
|
+
end
|
281
|
+
|
282
|
+
def GetThumbFilename
|
283
|
+
puts "Not implemented"
|
284
|
+
end
|
285
|
+
|
286
|
+
def GetVolume
|
287
|
+
parse(cmd())
|
288
|
+
end
|
289
|
+
|
290
|
+
def GetLogLevel
|
291
|
+
parse(cmd())
|
292
|
+
end
|
293
|
+
|
294
|
+
def QueryMusicDatabase
|
295
|
+
puts "Not implemented"
|
296
|
+
end
|
297
|
+
|
298
|
+
def QueryVideoDatabase
|
299
|
+
puts "Not implemented"
|
300
|
+
end
|
301
|
+
|
302
|
+
# Commands that Modify Settings
|
303
|
+
|
304
|
+
def AddToPlayList(media, playlist=nil, mask=nil, recursive=true)
|
305
|
+
if(recursive == true)
|
306
|
+
recursive = 1
|
307
|
+
else
|
308
|
+
recursive = 0
|
309
|
+
end
|
310
|
+
success?(parse(cmd(with_args(media, playlist, mask, recursive))))
|
311
|
+
end
|
312
|
+
|
313
|
+
def AddToSlideshow(media, mask="[pictures]", recursive=true)
|
314
|
+
if(recursive == true)
|
315
|
+
recursive = 1
|
316
|
+
else
|
317
|
+
recursive = 0
|
318
|
+
end
|
319
|
+
success?(parse(cmd(with_args(media, mask, recursive))))
|
320
|
+
end
|
321
|
+
|
322
|
+
def ClearPlayList(playlist=nil)
|
323
|
+
success?(parse(cmd(with_args(playlist))))
|
324
|
+
end
|
325
|
+
|
326
|
+
def ClearSlideshow
|
327
|
+
success?(parse(cmd()))
|
328
|
+
end
|
329
|
+
|
330
|
+
def Mute
|
331
|
+
success?(parse(cmd()))
|
332
|
+
end
|
333
|
+
|
334
|
+
def RemoveFromPlaylist(item, playlist=nil)
|
335
|
+
success?(parse(cmd(with_args(item, playlist))))
|
336
|
+
end
|
337
|
+
|
338
|
+
def SeekPercentage(percentage)
|
339
|
+
success?(parse(cmd(with_args(percentage))))
|
340
|
+
end
|
341
|
+
|
342
|
+
def SeekPercentageRelative(percentage)
|
343
|
+
success?(parse(cmd(with_args(percentage))))
|
344
|
+
end
|
345
|
+
|
346
|
+
def SetCurrentPlaylist(playlist)
|
347
|
+
success?(parse(cmd(with_args(playlist))))
|
348
|
+
end
|
349
|
+
|
350
|
+
def SetGUISetting(type, name, value)
|
351
|
+
success?(parse(cmd(with_args(type, name, value))))
|
352
|
+
end
|
353
|
+
|
354
|
+
def SetPlaylistSong(position)
|
355
|
+
success?(parse(cmd(with_args(position))))
|
356
|
+
end
|
357
|
+
|
358
|
+
def SetPlaySpeed(speed)
|
359
|
+
success?(parse(cmd(with_args(speed))))
|
360
|
+
end
|
361
|
+
|
362
|
+
def SlideshowSelect(filename)
|
363
|
+
success?(parse(cmd(with_args(filename))))
|
364
|
+
end
|
365
|
+
|
366
|
+
def SetVolume(volume)
|
367
|
+
success?(parse(cmd(with_args(volume))))
|
368
|
+
end
|
369
|
+
|
370
|
+
def SetLogLevel(level)
|
371
|
+
success?(parse(cmd(with_args(level))))
|
372
|
+
end
|
373
|
+
|
374
|
+
def SetAutoGetPictureThumbs(boolean=true)
|
375
|
+
success?(parse(cmd(with_args(boolean))))
|
376
|
+
end
|
377
|
+
|
378
|
+
# Commands that Generate Actions
|
379
|
+
|
380
|
+
def Action(code) # Sends a raw Action ID (see key.h)
|
381
|
+
success?(parse(cmd(with_args(code))))
|
382
|
+
end
|
383
|
+
|
384
|
+
def Exit
|
385
|
+
success?(parse(cmd()))
|
386
|
+
end
|
387
|
+
|
388
|
+
def KeyRepeat(rate)
|
389
|
+
success?(parse(cmd(with_args(rate))))
|
390
|
+
end
|
391
|
+
|
392
|
+
def Move(deltaX, deltaY)
|
393
|
+
success?(parse(cmd(with_args(deltaX, deltaY))))
|
394
|
+
end
|
395
|
+
|
396
|
+
def Pause
|
397
|
+
success?(parse(cmd()))
|
398
|
+
end
|
399
|
+
|
400
|
+
def PlayListNext
|
401
|
+
success?(parse(cmd()))
|
402
|
+
end
|
403
|
+
|
404
|
+
def PlayListPrev
|
405
|
+
success?(parse(cmd()))
|
406
|
+
end
|
407
|
+
|
408
|
+
def PlayNext
|
409
|
+
success?(parse(cmd()))
|
410
|
+
end
|
411
|
+
|
412
|
+
def PlayPrev
|
413
|
+
success?(parse(cmd()))
|
414
|
+
end
|
415
|
+
|
416
|
+
def PlaySlideshow(directory=nil, recursive=true)
|
417
|
+
success?(parse(cmd(with_args(directory, recursive))))
|
418
|
+
end
|
419
|
+
|
420
|
+
def PlayFile(filename, playlist=nil)
|
421
|
+
success?(parse(cmd(with_args(filename, playlist))))
|
422
|
+
end
|
423
|
+
|
424
|
+
def Reset
|
425
|
+
success?(parse(cmd()))
|
426
|
+
end
|
427
|
+
|
428
|
+
def Restart
|
429
|
+
success?(parse(cmd()))
|
430
|
+
end
|
431
|
+
|
432
|
+
def RestartApp
|
433
|
+
success?(parse(cmd()))
|
434
|
+
end
|
435
|
+
|
436
|
+
def Rotate
|
437
|
+
success?(parse(cmd()))
|
438
|
+
end
|
439
|
+
|
440
|
+
def SendKey(buttoncode)
|
441
|
+
success?(parse(cmd(with_args(buttoncode))))
|
442
|
+
end
|
443
|
+
|
444
|
+
def ShowPicture(filename)
|
445
|
+
success?(parse(cmd(with_args(filename))))
|
446
|
+
end
|
447
|
+
|
448
|
+
def Shutdown
|
449
|
+
success?(parse(cmd()))
|
450
|
+
end
|
451
|
+
|
452
|
+
def SpinDownHardDisk
|
453
|
+
success?(parse(cmd()))
|
454
|
+
end
|
455
|
+
|
456
|
+
def Stop
|
457
|
+
success?(parse(cmd()))
|
458
|
+
end
|
459
|
+
|
460
|
+
def TakeScreenshot(width=300, height=200, quality=90, rotation=0, download=true, filename="xbmc-screen.jpg", flash=true, imgtag=false)
|
461
|
+
if(imgtag)
|
462
|
+
imgtag = "imgtag"
|
463
|
+
else
|
464
|
+
imgtag = nil
|
465
|
+
end
|
466
|
+
parse(cmd(with_args(filename, flash, rotation, width, height, quality, download, imgtag)))
|
467
|
+
end
|
468
|
+
|
469
|
+
def Zoom(zoom)
|
470
|
+
success?(parse(cmd(with_args(zoom))))
|
471
|
+
end
|
472
|
+
|
473
|
+
##### END XBMC API
|
474
|
+
|
475
|
+
def initialize(host, port=nil, user=nil, pass=nil)
|
476
|
+
@@connection = Connection.new(host, port, user, pass)
|
477
|
+
end
|
478
|
+
|
479
|
+
def error?
|
480
|
+
not error.nil?
|
481
|
+
end
|
482
|
+
|
483
|
+
def print_error
|
484
|
+
$stderr.puts "Error: " + @error if @error != nil
|
485
|
+
end
|
486
|
+
|
487
|
+
def host
|
488
|
+
@@connection.host
|
489
|
+
end
|
490
|
+
|
491
|
+
def port
|
492
|
+
@@connection.port
|
493
|
+
end
|
494
|
+
|
495
|
+
# private members
|
496
|
+
private
|
497
|
+
|
498
|
+
def with_args(*args)
|
499
|
+
args.flatten! if args.length == 1
|
500
|
+
command = self.caller_method
|
501
|
+
command += "("
|
502
|
+
cmdargs = ""
|
503
|
+
args.each {|arg| cmdargs += (";" + (URI.escape(arg.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")))) unless arg.nil? }
|
504
|
+
cmdargs = cmdargs[1..-1]
|
505
|
+
command += cmdargs unless cmdargs.nil?
|
506
|
+
command += ")"
|
507
|
+
end
|
508
|
+
|
509
|
+
def cmd(command=nil)
|
510
|
+
command = self.caller_method if command.nil?
|
511
|
+
response = @@connection.exec(command)
|
512
|
+
end
|
513
|
+
|
514
|
+
def success?(res)
|
515
|
+
(not error? and not res.nil? and res == "OK")
|
516
|
+
end
|
517
|
+
|
518
|
+
def parse_resp(response)
|
519
|
+
doc = Hpricot(response)
|
520
|
+
list = (doc/"li")
|
521
|
+
if(list.length > 0)
|
522
|
+
text = list.inner_text
|
523
|
+
if(text[0,5] == "Error")
|
524
|
+
idx = text.index(':')
|
525
|
+
if(idx != nil)
|
526
|
+
@error = text[(idx+2)..-1]
|
527
|
+
else
|
528
|
+
@error = "Unknown error"
|
529
|
+
end
|
530
|
+
else
|
531
|
+
@error = nil
|
532
|
+
end
|
533
|
+
else # file download (screenshot)
|
534
|
+
return doc
|
535
|
+
end
|
536
|
+
list
|
537
|
+
end
|
538
|
+
|
539
|
+
def parse(response)
|
540
|
+
resp = parse_resp(response).inner_text.transliterate
|
541
|
+
return "" if error?
|
542
|
+
resp
|
543
|
+
end
|
544
|
+
|
545
|
+
def parse_aslist(response)
|
546
|
+
list = []
|
547
|
+
parse_resp(response).each {|item| list.push(item.inner_text.transliterate.chomp)}
|
548
|
+
return [] if error?
|
549
|
+
list
|
550
|
+
end
|
551
|
+
|
552
|
+
def parse_asdictlist(response, keys)
|
553
|
+
list = []
|
554
|
+
parse_aslist(response).each {|item| list.push((item.split(';').collect {|x| x.transliterate.chomp.rstrip}).to_hash(keys) )}
|
555
|
+
return [] if error?
|
556
|
+
list
|
557
|
+
end
|
558
|
+
|
559
|
+
def parse_asdict(response)
|
560
|
+
dict = {}
|
561
|
+
resp = parse_resp(response)
|
562
|
+
return dict if error?
|
563
|
+
resp.each {|item|
|
564
|
+
item = item.inner_text.transliterate
|
565
|
+
idx = item.index(':')
|
566
|
+
next if item == nil
|
567
|
+
key = item[0..idx-1]
|
568
|
+
value = item[idx+1..-1].chomp
|
569
|
+
dict[key]=value
|
570
|
+
}
|
571
|
+
dict
|
572
|
+
end
|
573
|
+
|
574
|
+
end
|
575
|
+
|
576
|
+
end
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nezetic-ruby-xbmc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Cedric TESSIER
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-05-15 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: hpricot
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.6.0
|
24
|
+
version:
|
25
|
+
description: ruby-xbmc is a ruby wrapper for the XBMC Web Server HTTP API. It provides a remote access to any XBMC running on the local network, in a simple way (methods follow the ones from XBMC API).
|
26
|
+
email: nezetic at gmail d o t com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files: []
|
32
|
+
|
33
|
+
files:
|
34
|
+
- README
|
35
|
+
- lib/ruby-xbmc.rb
|
36
|
+
has_rdoc: true
|
37
|
+
homepage: http://github.com/nezetic/ruby-xbmc
|
38
|
+
post_install_message:
|
39
|
+
rdoc_options: []
|
40
|
+
|
41
|
+
require_paths:
|
42
|
+
- lib
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: "0"
|
48
|
+
version:
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0"
|
54
|
+
version:
|
55
|
+
requirements: []
|
56
|
+
|
57
|
+
rubyforge_project:
|
58
|
+
rubygems_version: 1.2.0
|
59
|
+
signing_key:
|
60
|
+
specification_version: 2
|
61
|
+
summary: ruby-xbmc is a ruby wrapper for the XBMC Web Server HTTP API
|
62
|
+
test_files: []
|
63
|
+
|