nezetic-ncXBMC 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/README +14 -0
  2. data/bin/ncxbmc.rb +632 -0
  3. metadata +73 -0
data/README ADDED
@@ -0,0 +1,14 @@
1
+ ncXBMC
2
+ ==================
3
+
4
+ ncXBMC is a remote XBMC client, which aims to provide a full control of
5
+ the music player over a local network.
6
+
7
+ It can be used to browse library, manage playlist, and control playback.
8
+
9
+ The interface as been greatly inspired by ncmpc (http://hem.bredband.net/kaw/ncmpc/),
10
+ a curses client for the Music Player Daemon (MPD) (I'm a fan).
11
+
12
+
13
+ Usage: ncxbmc.rb [options] hostname
14
+
data/bin/ncxbmc.rb ADDED
@@ -0,0 +1,632 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ =begin
4
+ ncXBMC
5
+
6
+ ncXBMC is a remote XBMC client, which aims to provide a full control of
7
+ the music player over a local network.
8
+
9
+ It can be used to browse library, manage playlist, and control playback.
10
+
11
+ The interface as been greatly inspired by ncmpc (http://hem.bredband.net/kaw/ncmpc/),
12
+ a curses client for the Music Player Daemon (MPD) (I'm a fan).
13
+
14
+
15
+ Copyright (C) 2009 Cedric TESSIER
16
+
17
+ Contact: nezetic.info
18
+
19
+ This program is free software: you can redistribute it and/or modify
20
+ it under the terms of the GNU General Public License as published by
21
+ the Free Software Foundation, either version 3 of the License, or
22
+ (at your option) any later version.
23
+
24
+ This program is distributed in the hope that it will be useful,
25
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
26
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27
+ GNU General Public License for more details.
28
+
29
+ You should have received a copy of the GNU General Public License
30
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
31
+ =end
32
+
33
+
34
+ require 'optparse'
35
+
36
+ begin
37
+ require 'rubygems'
38
+ rescue LoadError
39
+ end
40
+
41
+ require 'ncurses'
42
+ require 'ruby-xbmc'
43
+
44
+ NCXMBC_DEFAULTPORT="8080"
45
+ NCXBMC_VERSION=0.2
46
+
47
+ module Interface
48
+ KEY_TAB = 9
49
+ KEY_ENTER = 10
50
+ KEY_SPACE = 32
51
+ KEY_RIGHT = 261
52
+ KEY_LEFT = 260
53
+ KEY_UP = 259
54
+ KEY_DOWN = 258
55
+ KEY_b = 98
56
+ KEY_c = 99
57
+ KEY_d = 100
58
+ KEY_f = 102
59
+ KEY_h = 104
60
+ KEY_m = 109
61
+ KEY_p = 112
62
+ KEY_RETURN = 127
63
+
64
+ class NcurseInterface
65
+ REFRESH_DELAY=1 # seconds
66
+ KEY_ESC=27
67
+
68
+ def initialize(xbmc)
69
+ @stdscr = Ncurses.initscr
70
+
71
+ Ncurses.curs_set(0)
72
+ Ncurses.noecho
73
+ Ncurses.keypad(@stdscr,TRUE)
74
+ Ncurses.cbreak
75
+ @stdscr.nodelay(true)
76
+
77
+ ObjectSpace.define_finalizer(self, self.class.method(:finalize).to_proc)
78
+
79
+ if Ncurses.has_colors?
80
+ Ncurses.start_color
81
+ Ncurses.use_default_colors
82
+ init_bgcolor()
83
+ end
84
+
85
+ @maxy=Ncurses.getmaxy(@stdscr)
86
+ @maxx=Ncurses.getmaxx(@stdscr)
87
+
88
+ @xbmc = xbmc
89
+
90
+ @wins = []
91
+ @wins << PlaylistWin.new(@stdscr, @xbmc)
92
+ @wins << LibraryWin.new(@stdscr, @xbmc)
93
+
94
+ @currentwin = 0
95
+ end
96
+
97
+ def refresh
98
+ @stdscr.refresh
99
+ @wins[@currentwin].refresh
100
+ end
101
+
102
+ def drawCurrentWin
103
+ @wins[@currentwin].draw
104
+ end
105
+
106
+ def UpdateCurrentWin
107
+ @wins[@currentwin].update
108
+ end
109
+
110
+ def run
111
+ self.drawCurrentWin
112
+ self.refresh
113
+
114
+ key=0
115
+ timespent=0
116
+ while key!=KEY_ESC
117
+ key=@stdscr.getch
118
+
119
+ if(key == KEY_TAB) # Tabs Cycling
120
+ @currentwin += 1
121
+ @currentwin = 0 if(@currentwin > (@wins.length - 1))
122
+
123
+ self.drawCurrentWin
124
+ self.refresh
125
+ next
126
+ end
127
+
128
+ @wins[@currentwin].handleKey(key) if key != -1
129
+
130
+ sleep(0.01)
131
+ timespent += 0.01
132
+
133
+ if(timespent >= REFRESH_DELAY)
134
+ timespent = 0
135
+ self.UpdateCurrentWin
136
+ end
137
+ end
138
+ end
139
+
140
+ protected
141
+
142
+ def init_bgcolor(pair=1, bgcolor=Ncurses::COLOR_BLACK)
143
+ Ncurses.init_pair(1, Ncurses::COLOR_WHITE, bgcolor)
144
+ Ncurses.init_pair(2, Ncurses::COLOR_YELLOW, bgcolor)
145
+ Ncurses.init_pair(3, Ncurses::COLOR_RED, bgcolor)
146
+ Ncurses.init_pair(4, Ncurses::COLOR_GREEN, bgcolor)
147
+ Ncurses.init_pair(5, Ncurses::COLOR_BLUE, bgcolor)
148
+ Ncurses.init_pair(6, Ncurses::COLOR_CYAN, bgcolor)
149
+ Ncurses.init_pair(7, Ncurses::COLOR_MAGENTA, bgcolor)
150
+ Ncurses.init_pair(8, Ncurses::COLOR_BLACK, bgcolor)
151
+ Ncurses.bkgd(Ncurses.COLOR_PAIR(pair))
152
+ end
153
+
154
+ private
155
+
156
+ def self.finalize(id)
157
+ Ncurses.echo()
158
+ Ncurses.nocbreak()
159
+ Ncurses.nl()
160
+ Ncurses.curs_set(1)
161
+
162
+ Ncurses.endwin
163
+ end
164
+ end
165
+
166
+ class TabWins
167
+
168
+ def initialize(pscreen, xbmc)
169
+ @stdscr = pscreen
170
+ @xbmc = xbmc
171
+
172
+ @title = ""
173
+
174
+ @maxy=Ncurses.getmaxy(@stdscr)
175
+ @maxx=Ncurses.getmaxx(@stdscr)
176
+
177
+ @header = Ncurses::WINDOW.new(2,@maxx,0,0)
178
+ @main = Ncurses::WINDOW.new(@maxy-2-2,@maxx,2,0)
179
+ @footer = Ncurses::WINDOW.new(2,@maxx,@maxy-2,0)
180
+
181
+ @selected = 0
182
+ @scroll = 0
183
+
184
+ @helpMSGCommon = "TAB switch between windows\nESC quit ncXBMC\n\n"
185
+ @helpMSG = ""
186
+ end
187
+
188
+ def refresh
189
+ @header.refresh
190
+ @main.refresh
191
+ @footer.refresh
192
+ end
193
+
194
+ def draw
195
+ self.drawHeader
196
+ self.drawMain
197
+ self.drawFooter
198
+ end
199
+
200
+ def update(rheader=false, rmain=false, rfooter=false)
201
+ if(rheader)
202
+ drawHeader
203
+ @header.refresh
204
+ end
205
+ if(rmain)
206
+ self.drawMain
207
+ @main.refresh
208
+ end
209
+ if(rfooter)
210
+ self.drawFooter
211
+ @footer.refresh
212
+ end
213
+ end
214
+
215
+ def handleKey(key)
216
+ #Ncurses.mvwaddstr(@main, 20, 1, "KeyCode: " + key.to_s)
217
+ #@main.refresh
218
+
219
+ case key
220
+ when KEY_h then
221
+ self.showHelp
222
+ end
223
+ end
224
+
225
+ protected
226
+
227
+ def drawHeader
228
+ @header.erase
229
+ @header.attron(Ncurses::A_BOLD)
230
+ Ncurses.mvwaddstr(@header, 0, 1, "Ncurses XBMC Client v." + NCXBMC_VERSION.to_s + " -- " + @title)
231
+ @header.attroff(Ncurses::A_BOLD)
232
+ @header.mvhline(1,0,Ncurses::ACS_HLINE, @maxx)
233
+ end
234
+
235
+ def drawMain
236
+ @main.erase
237
+ end
238
+
239
+ def drawFooter
240
+ @footer.erase
241
+ @footer.mvhline(0,0,Ncurses::ACS_HLINE, @maxx)
242
+ end
243
+
244
+ def handleScroll
245
+ maxwy = Ncurses.getmaxy(@main) - 1
246
+ if((@selected - @scroll) > maxwy)
247
+ @scroll += 1
248
+ elsif((@selected - @scroll) < 0)
249
+ @scroll -= 1
250
+ end
251
+ return maxwy
252
+ end
253
+
254
+ def showHelp
255
+ border = 15
256
+ title = "Help"
257
+
258
+ helpmsg = @helpMSGCommon + @helpMSG
259
+
260
+ lines = helpmsg.count("\n") + 3
261
+ helpwin = Ncurses::WINDOW.new(lines, @maxx-border, 2, (@maxx/2 - (@maxx-border)/2))
262
+ Ncurses.box(helpwin, Ncurses::ACS_VLINE, Ncurses::ACS_HLINE)
263
+ helpwin.attron(Ncurses::A_REVERSE)
264
+ Ncurses.mvwaddstr(helpwin, 0, (@maxx-border)/2 - (title.length + 2)/2, " #{title} ")
265
+ helpwin.attroff(Ncurses::A_REVERSE)
266
+
267
+ linenbr = 1
268
+ helpmsg.each { |line|
269
+ Ncurses.mvwaddstr(helpwin, linenbr, 2, line.chomp)
270
+ linenbr += 1
271
+ }
272
+ helpwin.refresh
273
+ end
274
+ end
275
+
276
+ class PlaylistWin < TabWins
277
+ def initialize(pscreen, xbmc)
278
+ super
279
+ @title = "Playlist"
280
+
281
+ @forcesel = 0
282
+ @fastRefresh = false
283
+ end
284
+
285
+ def drawHeader
286
+ super
287
+
288
+ volume = @xbmc.GetVolume.to_i
289
+ if(volume > 0)
290
+ volume_label = "Volume %d%%" % volume
291
+ else
292
+ volume_label = "Volume Muted"
293
+ end
294
+ Ncurses.mvwaddstr(@header, 0, @maxx - volume_label.length - 1, volume_label)
295
+ end
296
+
297
+ def drawMain
298
+ super
299
+
300
+ if(not @fastRefresh)
301
+ getCurrentPlaylist
302
+ getCurrentSong
303
+ else
304
+ @fastRefresh = false
305
+ end
306
+
307
+ return if @playlist.length == 1 and @playlist[0]["artist"].nil?
308
+
309
+ maxwy = self.handleScroll
310
+
311
+ idx = 0
312
+ @playlist.each { |song|
313
+ line = idx - @scroll
314
+ if(line >= 0)
315
+ break if(line > maxwy)
316
+
317
+ current = (@playing and @current_song["URL"] == song["path"])
318
+ if(current)
319
+ @main.attron(Ncurses.COLOR_PAIR(2)) if Ncurses.has_colors?
320
+ @main.attron(Ncurses::A_BOLD)
321
+ end
322
+ @main.attron(Ncurses::A_REVERSE) if(idx == @selected)
323
+ Ncurses.mvwaddstr(@main, line, 1, "#{song["artist"]} - #{song["title"]}")
324
+ if(current)
325
+ @main.attron(Ncurses.COLOR_PAIR(1)) if Ncurses.has_colors?
326
+ @main.attroff(Ncurses::A_BOLD)
327
+ end
328
+ @main.attroff(Ncurses::A_REVERSE) if(idx == @selected)
329
+ end
330
+ idx += 1
331
+ }
332
+
333
+ end
334
+
335
+ def drawFooter
336
+ super
337
+
338
+ getCurrentSong
339
+
340
+ if(@playing)
341
+ speed = @xbmc.GetPlaySpeed.to_i
342
+ @footer.mvwaddstr(0, 0, '=' * (@maxx * @current_song["Percentage"].to_i / 100) + (speed == 1 ? '0': (speed > 1 ? '>>':'<<')))
343
+ paused = (@current_song["PlayStatus"] == "Paused")
344
+ Ncurses.mvwaddstr(@footer, 1, 1, "Playing: #{@current_song["Artist"]} - #{@current_song["Title"]} #{(paused ? "(Pause)":"")}")
345
+ time_label = "["+@current_song["Time"]+"/"+@current_song["Duration"]+"]"
346
+ Ncurses.mvwaddstr(@footer, 1, @maxx - time_label.length - 1, time_label)
347
+ speed_label = "(%dX)" % speed
348
+ @footer.mvwaddstr(0, @maxx - speed_label.length - 1, speed_label) if(speed != 1)
349
+ end
350
+ end
351
+
352
+ def update(rheader=false, rmain=false, rfooter=true)
353
+ super
354
+
355
+ if(@playing) # new song playing, refresh playlist
356
+ if(not rmain and (@current_song["Changed"] == "True"))
357
+ self.drawMain
358
+ @main.refresh
359
+ end
360
+ end
361
+ end
362
+
363
+ def handleKey(key)
364
+ super
365
+
366
+ refresh_header = false
367
+ refresh_main = false
368
+ refresh_footer = false
369
+
370
+ case key
371
+ when KEY_LEFT then
372
+ @xbmc.SetVolume(@xbmc.GetVolume.to_i - 1)
373
+ refresh_header = true
374
+ when KEY_RIGHT then
375
+ @xbmc.SetVolume(@xbmc.GetVolume.to_i + 1)
376
+ refresh_header = true
377
+ when KEY_DOWN then
378
+ @selected += 1 if @selected < (@playlist.length - 1)
379
+ @fastRefresh = true
380
+ refresh_main = true
381
+ when KEY_UP then
382
+ @selected -= 1 if @selected > 0
383
+ @fastRefresh = true
384
+ refresh_main = true
385
+ when KEY_ENTER then
386
+ if(@xbmc.GetPlaySpeed.to_i != 1)
387
+ @xbmc.SetPlaySpeed(1)
388
+ else
389
+ @xbmc.SetPlaylistSong(@selected)
390
+ end
391
+ refresh_main = true
392
+ when KEY_d then
393
+ @xbmc.RemoveFromPlaylist(@selected)
394
+ @selected -= 1 if @selected >= (@playlist.length - 1)
395
+ @forcesel = @selected
396
+ refresh_main = true
397
+ when KEY_c then
398
+ @xbmc.Stop
399
+ @xbmc.ClearPlayList(XBMC::MUSIC_PLAYLIST)
400
+ @selected = 0
401
+ refresh_main = true
402
+ when KEY_f then
403
+ speed = @xbmc.GetPlaySpeed.to_i
404
+ newspeed = speed < 0 ? speed / 2 : speed * 2
405
+ newspeed = 1 if(newspeed == -1)
406
+ @xbmc.SetPlaySpeed(newspeed) if(speed < 32)
407
+ when KEY_b then
408
+ speed = @xbmc.GetPlaySpeed.to_i
409
+ newspeed = speed > 0 ? speed / 2 : speed * 2
410
+ newspeed = -2 if(newspeed == 0)
411
+ @xbmc.SetPlaySpeed(newspeed) if(speed > -32)
412
+ when KEY_m then
413
+ @xbmc.Mute
414
+ refresh_header = true
415
+ when KEY_p then
416
+ @xbmc.Pause
417
+ refresh_footer = true
418
+ end
419
+
420
+ self.update(refresh_header, refresh_main, refresh_footer)
421
+ end
422
+
423
+ def showHelp
424
+ @helpMSG = "UP select previous entry\n"
425
+ @helpMSG += "DOWN select next entry\n"
426
+ @helpMSG += "ENTER play selected entry\n"
427
+ @helpMSG += "d remove selected entry\n"
428
+ @helpMSG += "c clear current playlist\n\n"
429
+ @helpMSG += "RIGHT Volume +\n"
430
+ @helpMSG += "LEFT Volume -\n"
431
+ @helpMSG += "m mute volume\n\n"
432
+ @helpMSG += "f fast forward\n"
433
+ @helpMSG += "b fast rewind\n"
434
+ @helpMSG += "p pause playback"
435
+ super
436
+ end
437
+
438
+ def getCurrentSong
439
+ @current_song = @xbmc.GetCurrentlyPlaying
440
+ @playing = (@current_song != nil)
441
+ end
442
+
443
+ def getCurrentPlaylist
444
+ playlist = @xbmc.GetPlaylistContents
445
+ return if(playlist == @last_playlist)
446
+ @last_playlist = playlist
447
+
448
+ @selected = @forcesel
449
+ @forcesel = 0
450
+
451
+ @playlist = [] # cache tags infos for playlist
452
+ playlist.each { |file|
453
+ song = @xbmc.GetTagFromFilename(file)
454
+ @playlist.push({"path"=>file, "artist"=>song["Artist"], "title"=>song["Title"]})
455
+ }
456
+ end
457
+
458
+ end
459
+
460
+ class LibraryWin < TabWins
461
+
462
+ def initialize(pscreen, xbmc)
463
+ super
464
+ @title = "Library"
465
+ @deepth = 0
466
+ @lastdeepth = -1
467
+ @currentdir = nil
468
+ @history = []
469
+
470
+ end
471
+
472
+ def drawMain
473
+ super
474
+
475
+ if(@lastdeepth != @deepth) # refresh library entries list if needed
476
+ @list = @xbmc.GetMediaLocation("music", @currentdir)
477
+ @lastdeepth = @deepth
478
+ end
479
+
480
+ maxwy = self.handleScroll
481
+
482
+ idx = 0
483
+ @list.each { |entry|
484
+ line = idx - @scroll
485
+ if(line >= 0)
486
+ break if(line > maxwy)
487
+
488
+ @main.attron(Ncurses::A_REVERSE) if(idx == @selected)
489
+ Ncurses.mvwaddstr(@main, line, 1, "#{entry["name"]}")
490
+ @main.attroff(Ncurses::A_REVERSE) if(idx == @selected)
491
+ end
492
+ idx += 1
493
+ }
494
+ end
495
+
496
+ def drawFooter
497
+ super
498
+
499
+ histline = ""
500
+ @history.reverse.each {|old|
501
+ histline += " > " + old[:currentname]
502
+ }
503
+
504
+ Ncurses.mvwaddstr(@footer, 1, 1, histline)
505
+
506
+ nitems_label = @list.length.to_s + " items"
507
+ @footer.mvwaddstr(1, @maxx - nitems_label.length - 1, nitems_label)
508
+ end
509
+
510
+ def handleKey(key)
511
+ super
512
+
513
+ refresh_header = false
514
+ refresh_main = false
515
+ refresh_footer = false
516
+
517
+ case key
518
+ when KEY_DOWN then
519
+ @selected += 1 if @selected < (@list.length - 1)
520
+ refresh_main=true
521
+ when KEY_UP then
522
+ @selected -= 1 if @selected > 0
523
+ refresh_main=true
524
+ when KEY_ENTER then
525
+ if @list[@selected]["type"].to_i == XBMC::TYPE_DIRECTORY
526
+ @history.insert(0, {:currentdir=>@currentdir, :selected=>@selected, :scroll=>@scroll, :currentname=>@list[@selected]["name"]})
527
+ @currentdir = @list[@selected]["path"]
528
+ @selected = 0
529
+ @scroll = 0
530
+ @deepth += 1
531
+ end
532
+ refresh_main = true
533
+ refresh_footer = true
534
+ when KEY_RETURN then
535
+ return if(@history.length < 1)
536
+ oldentry = @history.shift
537
+ @currentdir = oldentry[:currentdir]
538
+ @selected = oldentry[:selected]
539
+ @scroll = oldentry[:scroll]
540
+ @deepth -= 1
541
+ refresh_main = true
542
+ refresh_footer = true
543
+ when KEY_SPACE then
544
+ @xbmc.AddToPlayList(@list[@selected]["path"], XBMC::MUSIC_PLAYLIST, "[music]")
545
+ @xbmc.SetCurrentPlaylist(XBMC::MUSIC_PLAYLIST)
546
+ #@xbmc.SetPlaylistSong(0)
547
+ when KEY_c then
548
+ @xbmc.Stop
549
+ @xbmc.ClearPlayList(XBMC::MUSIC_PLAYLIST)
550
+ end
551
+
552
+ self.update(refresh_header, refresh_main, refresh_footer)
553
+ end
554
+
555
+ def showHelp
556
+ @helpMSG = "UP select previous entry\n"
557
+ @helpMSG += "DOWN select next entry\n"
558
+ @helpMSG += "ENTER browse selected directory\n"
559
+ @helpMSG += "RETURN return into previous directory\n"
560
+ @helpMSG += "SPACE add selected directory/file to playlist\n\n"
561
+ @helpMSG += "c clear current playlist"
562
+ super
563
+ end
564
+ end
565
+ end
566
+
567
+ ##### MAIN ######
568
+
569
+ options = {}
570
+ inputopts = OptionParser.new do |opts|
571
+ options[:port] = NCXMBC_DEFAULTPORT
572
+
573
+ opts.banner = "Usage: %s [options] hostname" % File.basename($0)
574
+ opts.separator " "
575
+
576
+ opts.on("-v", "--version", "Print version") do |v|
577
+ options[:version] = v
578
+ end
579
+ opts.on("-p", "--port [NUMBER]", Integer,"Port used (default %d)" % NCXMBC_DEFAULTPORT) do |port|
580
+ options[:port] = port
581
+ end
582
+ opts.on("-U", "--user [NAME]", String, "Username used for authentication") do |name|
583
+ options[:user] = name
584
+ end
585
+ opts.on("-P", "--password [PASS]", String, "Password used for authentication") do |pass|
586
+ options[:pass] = pass
587
+ end
588
+ end
589
+
590
+ begin
591
+ inputopts.parse!
592
+ rescue OptionParser::InvalidOption => e
593
+ puts "Error: " + e
594
+ puts "\n" + inputopts.banner
595
+ exit 1
596
+ end
597
+
598
+ if(options[:version])
599
+ puts "ncXBMC version " + NCXBMC_VERSION.to_s
600
+ puts <<EOF
601
+
602
+ Copyright (C) 2009 Cedric TESSIER
603
+
604
+ This program may be redistributed under
605
+ the terms of the GPL v2 License
606
+ EOF
607
+ exit 0
608
+ end
609
+
610
+ if(ARGV.length != 1)
611
+ puts inputopts
612
+ exit 1
613
+ end
614
+
615
+ hostname = ARGV.first
616
+
617
+ xbmc = XBMC::XBMC.new(hostname, options[:port], options[:user], options[:pass])
618
+
619
+ begin
620
+ puts "Connected to " + xbmc.host + " (xbmc " + xbmc.GetSystemInfo(120).first + ")"
621
+ rescue XBMC::UnauthenticatedError => e
622
+ puts "ERROR: " + e
623
+ exit 1
624
+ rescue SocketError => e
625
+ puts "ERROR: Connection error"
626
+ puts "Please check given hostname (and/or port)"
627
+ exit 1
628
+ end
629
+
630
+ interface = Interface::NcurseInterface.new(xbmc)
631
+ interface.run
632
+
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nezetic-ncXBMC
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.1
5
+ platform: ruby
6
+ authors:
7
+ - Cedric TESSIER
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-05-16 00:00:00 -07:00
13
+ default_executable: ncxbmc.rb
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: ncurses
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0.9"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: ruby-xbmc
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0.1"
34
+ version:
35
+ description: ncXBMC is a remote XBMC client, with an ncurses interface, which aims to provide a full control of the music player over a local network. It can be used to browse library, manage playlist, and control playback.
36
+ email: nezetic at gmail d o t com
37
+ executables:
38
+ - ncxbmc.rb
39
+ extensions: []
40
+
41
+ extra_rdoc_files: []
42
+
43
+ files:
44
+ - README
45
+ - bin/ncxbmc.rb
46
+ has_rdoc: false
47
+ homepage: http://github.com/nezetic/ncXBMC
48
+ post_install_message:
49
+ rdoc_options: []
50
+
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ version:
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ requirements: []
66
+
67
+ rubyforge_project:
68
+ rubygems_version: 1.2.0
69
+ signing_key:
70
+ specification_version: 2
71
+ summary: ncXBMC is a remote XBMC client, with an ncurses interface
72
+ test_files: []
73
+