candelabra 0.0.1 → 1.0.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.
@@ -0,0 +1,142 @@
1
+ module Candelabra
2
+ # The Pianobar module of Candelabra handles starting and
3
+ # stopping of pianobar. The module will contain the PID of the
4
+ # process. It will also be able to kill of the pianobar's
5
+ # running on the system
6
+ #
7
+ # For Example:
8
+ # Candelabra::Pianobar.start
9
+ # # => pianobar has started
10
+ module Pianobar
11
+ # Give me super powers and the ability to call all the
12
+ # methods in this file.
13
+ module_function
14
+
15
+ # The accessor for the PID. If this is nil then no process
16
+ # has been started
17
+ #
18
+ # Returns int or nil
19
+ def pid
20
+ return @pid unless @pid.nil?
21
+ @pid = execute.command :pid
22
+ end
23
+
24
+ # Check to determine if pianobar is running anywhere on the system
25
+ #
26
+ # Returns true or false
27
+ def running?
28
+ !pid.nil?
29
+ end
30
+
31
+ # Start the pianobar. ( bet you couldn't have guessed that
32
+ # one ) It will take the output pianobar and redirect it to
33
+ # logs/out.log in the gem folder.
34
+ #
35
+ # Example:
36
+ # Candelabra::Pianobar.start
37
+ # # => gives you the process ID
38
+ #
39
+ # Returns the process ID a.k.a pid
40
+ def start
41
+ @pid = execute.command :start
42
+ end
43
+
44
+ # Die pianobar die!!!! Yeah that is what it does. If you have
45
+ # a PID then this will send the kill command to that process
46
+ #
47
+ # Example:
48
+ # Candelabra::Pianobar.stop
49
+ # # => pianobar is done for
50
+ #
51
+ # Returns nothing
52
+ def stop
53
+ execute.commands[:stop] = Stop.new(pid)
54
+ execute.command :stop
55
+ end
56
+
57
+
58
+ # First stop all running pianobar instances and then start up a new one
59
+ #
60
+ # Example:
61
+ # Candelabra::Pianobar.restart
62
+ # # => pianobar is stoped and then restarted
63
+ #
64
+ # Returns nothing
65
+ def restart
66
+ stop_all
67
+ start
68
+ end
69
+
70
+ # When killing one pianobar is not enough. Kill them all.
71
+ # This will send a system command to kill all of the
72
+ # pianobars running on the system. This is useful because of
73
+ # rouge pianobars and stuff
74
+ #
75
+ # Example:
76
+ # Candelabra::Pianobar.stop_all
77
+ # # => and they are all dead
78
+ #
79
+ # Returns nothing useful
80
+ def stop_all
81
+ @pid = execute.command :stop_all
82
+ end
83
+
84
+ # An implementation of the command pattern
85
+ # see the GOF book...
86
+ def execute
87
+ @execute ||= Execute.new
88
+ end
89
+
90
+ class Execute
91
+ attr_accessor :commands
92
+
93
+ def initialize
94
+ @commands = {
95
+ :start => Start.new,
96
+ :stop_all => StopAll.new,
97
+ :pid => PID.new
98
+ }
99
+ end
100
+
101
+ def command(command)
102
+ @commands[command].go if @commands[command]
103
+ end
104
+ end
105
+
106
+ # The following classes are commands invoked with the 'go' method
107
+ class Start
108
+ def go
109
+ pid = spawn( 'pianobar', :in => File.open( Installer.input_path, 'r+' ), :out => File.open( Installer.output_path, 'w+' ) )
110
+ ::Process.detach(pid)
111
+ pid
112
+ end
113
+ end
114
+
115
+ class StopAll
116
+ def go
117
+ %x[killall pianobar]
118
+ nil
119
+ end
120
+ end
121
+
122
+ class Stop
123
+ def initialize(pid)
124
+ @pid = pid
125
+ end
126
+
127
+ def go
128
+ return if @pid.nil?
129
+ ::Process.kill('HUP', @pid)
130
+ @pid = nil
131
+ end
132
+ end
133
+
134
+ class PID
135
+ def go
136
+ pid = %x[ps -a | grep pianobar$].split(' ').first
137
+ pid = pid.to_i unless pid.nil?
138
+ end
139
+ end
140
+
141
+ end
142
+ end
@@ -0,0 +1,152 @@
1
+ module Candelabra
2
+ module Remote
3
+ module_function
4
+
5
+ # This is a list of avaiable commands for pianobar The list
6
+ # here is the list that we are string with. There are a few
7
+ # more commands but thoses commands might have multple input
8
+ # request and we have to figure out how to do that for the
9
+ # user
10
+ #
11
+ # Returns hash of commands and key
12
+ def commands
13
+ {
14
+ :pause => 'p',
15
+ :continue => 'p',
16
+ :love => '+',
17
+ :ban => '-',
18
+ :bookmark => 'b',
19
+ :info => 'i',
20
+ :skip => 'n',
21
+ :next => 'n',
22
+ :quit => 'q',
23
+ :change_station => 's',
24
+ :tired => 't',
25
+ :upcomming => 'u',
26
+ :quick_mix => 'x',
27
+ }
28
+ end
29
+
30
+ # Send the command to pianobar through the fifo file. If Pianobar is not running
31
+ # it will start pianobar, but not send the command.
32
+ #
33
+ # Example:
34
+ # If pianobar is NOT running
35
+ # Candelabra::Remote.execute_command :pause
36
+ # # => just starts pianobar. It doesn't pause it
37
+ #
38
+ # If pianobar IS running
39
+ # Candelabra::Remote.execute_command :pause
40
+ # # => pauses pianobar
41
+ #
42
+ # Returns command you passed in
43
+ def execute_command cmd
44
+ return Candelabra::Pianobar.start unless Candelabra::Pianobar.running?
45
+ if commands.include? cmd
46
+ %x[ echo #{commands[cmd]} > #{Candelabra::Installer.ctl_path} ]
47
+ else
48
+ %x[ echo #{cmd} > #{Candelabra::Installer.ctl_path} ]
49
+ end
50
+ cmd
51
+ end
52
+
53
+ # Wrapper for all the commands. This will give you the ability to call the following methods
54
+ #
55
+ # Example:
56
+ # Candelabra::Remote.pause
57
+ # # => Candelabra.Remote.execute_command :pause
58
+ #
59
+ # Candelabra::Remote.love
60
+ # # => Candelabra.Remote.execute_command :love
61
+ #
62
+ # Returns result of execute_command or method missing
63
+ def method_missing(method,*args)
64
+ if commands.keys.include? method.to_sym
65
+ execute_command method.to_sym
66
+ else
67
+ super method, args
68
+ end
69
+ end
70
+
71
+ # When changing stations the user needs to get the list of stations.
72
+ #
73
+ # Example:
74
+ # Candelabra::Remote.change_station
75
+ # # => [ list of stations ]
76
+ # Candelabra::Remote.change_station 6
77
+ # # => go to the 6th station
78
+ #
79
+ # Returns list of stations _or_ changes the station to the requested station
80
+ def change_station( station_number = nil )
81
+ if station_number.nil?
82
+ stations
83
+ else
84
+ execute_command( :change_station )
85
+ execute_command( "s" + station_number.to_s ) unless station_number.nil?
86
+ end
87
+ end
88
+
89
+ def station_ids
90
+ return @ids unless @ids.nil?
91
+ @ids = []
92
+ stations.each_with_index do |station,index|
93
+ change_station(index)
94
+ @ids << station_id
95
+ end
96
+ pause # this is because the it will play the last station other wise
97
+ @ids
98
+ end
99
+
100
+ def station_id
101
+ /(\d+)/ =~ info
102
+ $1
103
+ end
104
+
105
+ def info
106
+ execute_command( :info )
107
+ song_info = ''
108
+ output do |io|
109
+ io.lines.each do |line|
110
+ /(Station .+ \(\d+\))/ =~ line
111
+ if $1
112
+ song_info = $1
113
+ break
114
+ end
115
+ end
116
+ end
117
+ song_info
118
+ end
119
+
120
+ # Get a list of stations from the system
121
+ # read the station list from the command line
122
+ #
123
+ # Returns an array of stations
124
+ def stations
125
+ list = []
126
+ execute_command( :change_station )
127
+ output do |io|
128
+ io.lines.each do |line|
129
+ /(\[\?\])/ =~ line
130
+ break if $1 == '[?]' # this denotes the use input for which station to change to
131
+ list << $1 if /(#{list.size}\).+)/ =~ line
132
+ end
133
+ end
134
+ list
135
+ end
136
+
137
+ def flush
138
+ output {|io| io.flush }
139
+ end
140
+
141
+ # The out put file for the commands
142
+ # This contains all the output from pianobar
143
+ #
144
+ # Yields and IO reader for pianobar's output
145
+ def output
146
+ File.open( Candelabra::Installer.output_path, 'r+' ) do |io|
147
+ yield( io )
148
+ end
149
+ end
150
+
151
+ end
152
+ end
@@ -0,0 +1,93 @@
1
+ module Candelabra
2
+ # This class gives access to candelabra from the command line
3
+ # It has several useful functions like starting, stoping, and
4
+ # firing events to candelabra
5
+ #
6
+ # Examples:
7
+ # candelabra start
8
+ # # => I will let you guess what this one does
9
+ #
10
+ # candelabra stop
11
+ # # => Yup it does that you are thinking
12
+ #
13
+ # candelabra restart
14
+ # # => see above
15
+ #
16
+ # candelabra event -e on_error
17
+ # # => send an error event to candelabra
18
+ class Runner
19
+ attr_reader :config, :options, :command, :data
20
+
21
+ # Set up the running for Candelabra. Parse out command and
22
+ # get all the data required for any command
23
+ #
24
+ # Returns...it's the initializer
25
+ def initialize(args)
26
+ @command = args.shift
27
+ end
28
+
29
+ # Take in the arguments from the command line and parse out any
30
+ # options and set up the options hash
31
+ #
32
+ # Returns parsed optionr
33
+ def parse( args )
34
+ @options ={}
35
+ Candelabra::Configuration.go do |config|
36
+ OptionParser.new( args ) do |opts|
37
+ opts.banner = 'Usage: candelabra [command] [opts]'
38
+
39
+ opts.on( '-e','--event [EVENT=DATA]',
40
+ 'Send the EVENT to Candelabra.',
41
+ 'if the extra DATA is supplied',
42
+ 'set the EVENT to the DATA.' ) do |event_command|
43
+
44
+ event, cmd = event_command.split('=')
45
+ config.send( event + '=', cmd ) if cmd
46
+ @options[event] = true
47
+ end
48
+
49
+ opts.on_tail( '-h', '--help', 'Show this message' ) do
50
+ puts opts
51
+ exit
52
+ end
53
+
54
+ opts.on_tail( '-v', '--version', 'Show Candelabra Version' ) do
55
+ puts "Candelabra's Version is: #{ Candelabra::VERSION }"
56
+ exit
57
+ end
58
+
59
+ end.parse!
60
+ end
61
+
62
+ Candelabra::Configuration.instance
63
+ end
64
+
65
+ # Execute the given command. Also fire off any events that
66
+ # occur in the system
67
+ #
68
+ # Returns nothing special
69
+ def run
70
+ # here comes brute
71
+ cmds = Remote.commands.keys.map{|x| x.to_s }.abbrev
72
+ case command
73
+ when 'start'
74
+ Candelabra::Pianobar.start
75
+ when 'stop'
76
+ Candelabra::Pianobar.stop
77
+ when 'restart'
78
+ Candelabra::Pianobar.restart
79
+ when 'install'
80
+ Candelabra::Installer.run
81
+ when 'event'
82
+ # NOTE: this is mainly for debugging
83
+ puts "On Song Start: #{ config.on_song_start }" if options['on_song_start']
84
+ puts "On Song Finish: #{ config.on_song_finish }" if options['on_song_finish']
85
+ puts "On Error: #{ config.on_error }" if options['on_error']
86
+ when *cmds.keys
87
+ Remote.send cmds[command].to_sym
88
+ else
89
+ puts "No command given"
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,4 @@
1
+ event_command = <%= exe_path %>
2
+ user = <%= @username %>
3
+ password = <%= @password %>
4
+ autostart_station = <%= station %>
@@ -0,0 +1,11 @@
1
+
2
+ Installing Candelabra Version <%= Candelabra::VERSION %>
3
+
4
+ Welcome to Candelabra!! Before you continue through the
5
+ installer make sure that you have an account with Pandora
6
+ and at least ONE station configured. Please enjoy.
7
+
8
+ cajun
9
+ mwoods79
10
+ lex148
11
+
@@ -0,0 +1,5 @@
1
+
2
+ Configuring Pianobar account
3
+
4
+ Enter your Pandora's account information
5
+
@@ -0,0 +1,11 @@
1
+
2
+ Checking Dependencies
3
+
4
+ => Detecting OS................................................................<%= which_os %>
5
+ => Detecting Package Manager...................................................<%= package_manager %>
6
+ => Detecting Pianobar..........................................................<%= exe_installed %>
7
+ => Detecting Control File......................................................<%= ctl_file %>
8
+ => Detecting Notifyer..........................................................<%= has_notifier %>
9
+
10
+ => Ok to install...............................................................<%= ok %>
11
+
@@ -0,0 +1,96 @@
1
+ module Candelabra
2
+ # This module contains installer specific instructions for
3
+ # Ubuntu using home bree Home apt_get is the best package
4
+ # manager for Ubuntu right now and the package manager that
5
+ # is going to be supported. Include this module into your
6
+ # class/module and you will be able to install using home
7
+ # apt_get.
8
+ #
9
+ # NOTE: This module will only be active if the os is Ubuntu
10
+ module Ubuntu
11
+ module InstanceMethods
12
+ # Installs the requested package using home apt_get. If the
13
+ # package is already installed home apt_get will not
14
+ # install it
15
+ #
16
+ # Example:
17
+ # Candelabra::Install.install 'pianobar'
18
+ # # => sudo apt-get install pianobar
19
+ #
20
+ # Returns standard output from home apt_get
21
+ def install lib
22
+ `gksudo apt-get install #{lib}` if has_installer?
23
+ end
24
+
25
+ # Gets the path of home apt-get. If it's somewere on your
26
+ # system this finds it. Candelabra assumes that you don't
27
+ # use sudo to install the apt_get packages
28
+ #
29
+ # Example:
30
+ # Candelabra::Install.apt_get_path
31
+ # # => /usr/bin/apt-get
32
+ #
33
+ # Returns a string
34
+ def installer_path
35
+ %x[which apt-get].chomp
36
+ end
37
+
38
+ # Simple check to determine if home apt_get is installed
39
+ #
40
+ # Example:
41
+ # Candelabra::Install.has_apt_get?
42
+ # # => On osx it should be true
43
+ # # => On ubuntu it should be false
44
+ #
45
+ # Returns true if home apt_get is there
46
+ def has_installer?
47
+ !installer_path.nil?
48
+ end
49
+
50
+ def os
51
+ 'Ubuntu\Linux'
52
+ end
53
+
54
+ def notify?
55
+ !%x[which notify-send].chomp.nil?
56
+ end
57
+
58
+ def notify
59
+ `notify-send -i #{File.realpath(art_work)} "Pianobar - #{stationName}" "Now Playing: #{ artist } - #{ title }"`
60
+ end
61
+ end
62
+
63
+ # Load the installer methods IF this is the correct OS
64
+ def self.extended klass
65
+ klass.extend( InstanceMethods ) if linux?
66
+ end
67
+
68
+ # Load the installer methods IF this is the correct OS
69
+ def self.included klass
70
+ klass.send( :include, InstanceMethods ) if linux?
71
+ end
72
+
73
+ # This method will say if the OS is Ubuntu or not
74
+ #
75
+ # Example:
76
+ # [ On Ubuntu ] linux?
77
+ # # => true
78
+ #
79
+ # [ On OSX ] linux?
80
+ # # => false
81
+ #
82
+ # Returns true for Ubuntu
83
+ def self.linux?
84
+ /linux/ =~ RbConfig::CONFIG["target_os"]
85
+ end
86
+ end
87
+ end
88
+
89
+
90
+ __END__
91
+ notify-send "Pianobar - $stationName" "Now Playing: $artist - $title"
92
+ if [ "$pRet" -ne 1 ]; then
93
+ notify-send "Pianobar - ERROR" "$1 failed: $pRetStr"
94
+ elif [ "$wRet" -ne 1 ]; then
95
+ notify-send "Pianobar - ERROR" "$1 failed: $wRetStr"
96
+ fi
@@ -1,3 +1,3 @@
1
1
  module Candelabra
2
- VERSION = "0.0.1"
2
+ VERSION = "1.0.0"
3
3
  end
data/lib/candelabra.rb CHANGED
@@ -1,3 +1,16 @@
1
- module Candelabra
2
- # Your code goes here...
1
+ # Pulling in all the libs we need to get the job done
2
+ %w(shell fileutils singleton optparse net/http erb abbrev).each do |lib|
3
+ require lib
4
+ end
5
+
6
+ # NOTE: These must be first.
7
+ dir = File.dirname(__FILE__)
8
+ require "#{dir}/candelabra/osx.rb"
9
+ require "#{dir}/candelabra/ubuntu.rb"
10
+
11
+ # Requiring all of the files in the lib dir. kinda cool ( i guess
12
+ # ). This way we don't have to worry about loading any of the
13
+ # files by hand.
14
+ Dir[File.join File.dirname(__FILE__), 'candelabra', '*.rb'].each do |file|
15
+ require file
3
16
  end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ describe Candelabra do
4
+ it 'should have a version number' do
5
+ Candelabra::VERSION.must_be_instance_of String
6
+ end
7
+ end
@@ -0,0 +1,81 @@
1
+ require 'helper'
2
+
3
+ describe Candelabra::Configuration do
4
+ before(:each) do
5
+ Candelabra::Configuration.go { |config| }
6
+ @config = Candelabra::Configuration.instance
7
+ end
8
+
9
+ describe 'setting up configuration' do
10
+ it 'should be able to set "auto_restart"' do
11
+ Candelabra::Configuration.go do |config|
12
+ config.auto_restart = false
13
+ end
14
+
15
+ @config.auto_restart.must_equal false
16
+ end
17
+
18
+ describe 'events' do
19
+ it 'should be able to set "on_song_start" to a lambda' do
20
+ Candelabra::Configuration.go do |config|
21
+ config.on_song_start = lambda { 'song_started' }
22
+ end
23
+
24
+ @config.on_song_start.must_equal 'song_started'
25
+ end
26
+
27
+ it 'should be able to set "on_song_start" to a primitive' do
28
+ Candelabra::Configuration.go do |config|
29
+ config.on_song_start = 'another_song'
30
+ end
31
+
32
+ @config.on_song_start.must_equal 'another_song'
33
+ end
34
+
35
+ it 'should be able to set "on_song_finish" to a lambda' do
36
+ Candelabra::Configuration.go do |config|
37
+ config.on_song_finish = lambda { 'song_finished' }
38
+ end
39
+
40
+ @config.on_song_finish.must_equal 'song_finished'
41
+ end
42
+
43
+ it 'should be able to set "on_song_finish" to a primitive' do
44
+ Candelabra::Configuration.go do |config|
45
+ config.on_song_finish = 'another_song_is_done'
46
+ end
47
+
48
+ @config.on_song_finish.must_equal 'another_song_is_done'
49
+ end
50
+ end
51
+
52
+ end
53
+
54
+ describe 'event handler' do
55
+ it 'should be able to set "event_handler"' do
56
+ handler = Object.new
57
+ Candelabra::Configuration.go do |config|
58
+ config.event_handler = handler
59
+ end
60
+
61
+ @config.event_handler.must_equal handler
62
+ end
63
+
64
+ it 'should have a handler' do
65
+ Candelabra::Configuration.go do |config|
66
+ config.event_handler = Object.new
67
+ end
68
+
69
+ @config.handler?.must_equal true
70
+ end
71
+
72
+ it 'should call the handler "on_song_start"' do
73
+ handler = OpenStruct.new :on_song_start => 'song_started'
74
+ Candelabra::Configuration.go do |config|
75
+ config.event_handler = handler
76
+ end
77
+
78
+ @config.on_song_start.must_equal 'song_started'
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,24 @@
1
+ require 'helper'
2
+
3
+ describe Candelabra::EventCmd do
4
+ before( :each ) do
5
+ @data = ["artist=Dean Martin\n", "title=Sway\n", "album=Dino: The Essential Dean Martin\n", "stationName=Cake Radio\n", "pRet=1\n", "pRetStr=Everything is fine :)\n", "wRet=1\n", "wRetStr=Everything's fine :)\n", "songDuration=0\n", "songPlayed=0\n", "rating=0\n"]
6
+ @handler = Candelabra::EventCmd.new( [ 'hah' ] )
7
+ end
8
+
9
+ it 'should be able to parse ARTIST' do
10
+ @handler.parse @data
11
+ @handler.artist.must_equal 'Dean Martin'
12
+ end
13
+
14
+ it 'should be able to parse TITLE' do
15
+ @handler.parse @data
16
+ @handler.title.must_equal 'Sway'
17
+ end
18
+
19
+ it 'should be able to parse ALBUM' do
20
+ @handler.parse @data
21
+ @handler.album.must_equal 'Dino: The Essential Dean Martin'
22
+ end
23
+ end
24
+
data/spec/helper.rb ADDED
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'ostruct'
4
+ require 'minitest/autorun'
5
+ require 'minitest/spec'
6
+ require 'minitest/pride'
7
+
8
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
9
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
10
+
11
+ require 'candelabra'
12
+
13
+ def clean_up
14
+ begin
15
+ yield
16
+ ensure
17
+ # NOTE: this give a message in the console stating you don't
18
+ # own this process. The test seem to work just fine.
19
+ %x[killall pianobar]
20
+ end
21
+ end
22
+
23
+ def ctl_file
24
+ # TODO: clear out the file before we start using it
25
+ File.open( Candelabra::Installer.ctl_path, ( File::RDONLY | File::NONBLOCK ) ) do |file|
26
+ yield( file )
27
+ end
28
+ end