candelabra 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,6 @@
1
1
  pkg/*
2
2
  *.gem
3
3
  .bundle
4
+ *.swp
5
+ logs/*
6
+ img.*
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.9.2@candelabra --create
data/Gemfile.lock ADDED
@@ -0,0 +1,17 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ candelabra (0.0.1)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ minitest (2.0.2)
10
+
11
+ PLATFORMS
12
+ ruby
13
+
14
+ DEPENDENCIES
15
+ bundler (~> 1.0.0)
16
+ candelabra!
17
+ minitest (>= 2.0.2)
data/README.md ADDED
@@ -0,0 +1,18 @@
1
+ The candelbra is on top of the piano....bar
2
+ ===========================================
3
+
4
+ # Candelbra
5
+ - is the traditional term for a set of multiple decorative
6
+ candlesticks, each of which often holds a candle on each of
7
+ multiple arms or branches connected to a column or pedestal.
8
+
9
+ This is not a candlestick. It is a wrapper lib for pianobar.
10
+ I will handle the installtion, configuration, and remote
11
+ controlling of pianobar. It can support multiple user accounts
12
+ and the switching between them.
13
+
14
+ There is a command line access to the lib as well as a ruby api.
15
+
16
+ ## Examples: ##
17
+
18
+ TODO: put the examples here.
data/Rakefile CHANGED
@@ -1,2 +1,11 @@
1
1
  require 'bundler'
2
+ require 'rake/testtask'
2
3
  Bundler::GemHelper.install_tasks
4
+
5
+ Rake::TestTask.new(:test) do |test|
6
+ test.libs << 'lib' << 'spec'
7
+ test.pattern = './spec/**/*_spec.rb'
8
+ test.verbose = true
9
+ end
10
+
11
+ task :default => :test
data/bin/candelabra ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require File.dirname(__FILE__) + '/../lib/candelabra'
5
+
6
+ # If the input comes from the terminal (i.e. user) then have
7
+ # candelabra handle it as user input, otherwise handle the input
8
+ # as an event from another application.
9
+ if $stdin.tty?
10
+ runner = Candelabra::Runner.new ARGV
11
+ else
12
+ runner = Candelabra::EventCmd.new ARGV
13
+ end
14
+
15
+ runner.run
data/candelabra.gemspec CHANGED
@@ -14,9 +14,8 @@ Gem::Specification.new do |s|
14
14
  s.required_rubygems_version = ">= 1.3.6"
15
15
  s.rubyforge_project = "candelabra"
16
16
 
17
- s.add_development_dependency "bundler" , ">= 1.0.0"
17
+ s.add_development_dependency "bundler" , "~> 1.0.0"
18
18
  s.add_development_dependency "minitest" , ">= 2.0.2"
19
- s.add_development_dependency "tomdoc" , "= 0.1.0"
20
19
 
21
20
  s.files = `git ls-files`.split("\n")
22
21
  s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
@@ -0,0 +1,50 @@
1
+ module Candelabra
2
+ class Configuration
3
+ include Singleton
4
+
5
+ attr_accessor :auto_restart, :event_handler, :in_installer
6
+ attr_writer :on_song_start, :on_song_finish, :on_error
7
+
8
+ class << self
9
+ # Initilize the configuration
10
+ def go
11
+ clear
12
+ yield self.instance
13
+ end
14
+
15
+ # Clear out the old settings in the configuration
16
+ def clear
17
+ auto_restart, event_handler = nil,nil
18
+ @on_song_start, @on_song_finish, @on_error = nil,nil,nil
19
+ end
20
+ end
21
+
22
+ # Check to determine if the hander has been set yet or not
23
+ def handler?
24
+ !event_handler.nil?
25
+ end
26
+
27
+ # Call the event requested by the system
28
+ #
29
+ # Returns what ever the system is configured to or nil
30
+ def call_event( event )
31
+ if handler?
32
+ event_handler.send( event )
33
+ elsif instance_variable_get( "@" + event.to_s ).respond_to?( 'call' )
34
+ instance_variable_get( "@" + event.to_s ).send( :call )
35
+ else
36
+ instance_variable_get( "@" + event.to_s )
37
+ end
38
+ end
39
+
40
+ # short cut way of calling the system
41
+ def method_missing( method, *args )
42
+ if method.to_s =~ /on_/
43
+ call_event( method )
44
+ else
45
+ super method, *args
46
+ end
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,62 @@
1
+ module Candelabra
2
+ class EventCmd
3
+ include OSX
4
+ include Ubuntu
5
+
6
+ attr_reader :command, :artist, :title, :album, :stationName, :coverArt
7
+
8
+ # Inigialize the Event Command with the given command
9
+ # Once we have the command we can preform different actions
10
+ def initialize(args)
11
+ @command = args.shift
12
+ end
13
+
14
+ # Run the command. Part of running the command
15
+ def run
16
+ parse( $stdin )
17
+ case command
18
+ when 'songstart'
19
+ notify
20
+ Remote.flush
21
+ when 'userlogin'
22
+ unless @pRet.to_i == 1
23
+ #`ps a | grep 'candelabra install' | cut -c1-5`.split("\n").each{|id| `kill #{id}` unless Process.pid == id.to_i }
24
+ `ps | grep candelabra`.split("\n").map{ |p| p.split(" ").last }.each{|x| `killall #{x}`}
25
+ end
26
+
27
+ else
28
+ #`notify-send #{@pRet}`
29
+ #`notify-send #{command}`
30
+ #`notify-send #{command}`
31
+ #instance_variables.each do |i|
32
+ # `notify-send #{i}`
33
+ #end
34
+ end
35
+ end
36
+
37
+ # Parse out the data from stdin. This will set instance vars
38
+ # that are named the same as the input from pianobar
39
+ #
40
+ # Retruns nothing
41
+ def parse(data)
42
+ data.each do |key_value|
43
+ key, value = key_value.chomp.split('=')
44
+ key = key
45
+ instance_variable_set( "@#{key}".to_sym, value )
46
+ end
47
+ end
48
+
49
+ # The 2011 release of pianobar supports album art. If wen
50
+ # have album are the it will be displayed in the notification
51
+ #
52
+ # Returns nil or the path of the file
53
+ def art_work
54
+ if coverArt
55
+ Dir.glob('*.jpg').each { |imge| File.delete(imge) }
56
+ File.open( 'img.jpg', 'wb' ) { |f| f.write Net::HTTP.get( URI.parse( coverArt ) ) }
57
+ Dir.glob('*.jpg').first
58
+ end
59
+ end
60
+ end
61
+ end
62
+
@@ -0,0 +1,70 @@
1
+ # This is used to colorize the ouput.
2
+ #
3
+ # Example usage
4
+ #
5
+ # "foo".red # => \033[0;31mfoo\033[0m
6
+ #
7
+ # This code was borrowed from https://github.com/stefanpenner/terminal-color
8
+ # A big thanks this was much more sophisticated than my naive approach.
9
+ #
10
+ # class String
11
+ # def red
12
+ # "\033[0;31m#{self}\033[0m"
13
+ # end
14
+ # end
15
+ #
16
+ # If you need colorization in your app and don't minde dependencies it is highly
17
+ # recomended that you use the terminal-color or rainbow gem.
18
+
19
+ class String
20
+ COLORS = {
21
+ :black => '0',
22
+ :red => '1',
23
+ :green => '2',
24
+ :yellow => '3',
25
+ :blue => '4',
26
+ :magenta => '5',
27
+ :cyan => '6',
28
+ :white => '7'
29
+ }
30
+
31
+ FORMAT_CODES = {
32
+ :bold => '1',
33
+ :italic => '3',
34
+ :underline => '4',
35
+ :blink => '5',
36
+ }
37
+
38
+ def ansi_formatted
39
+ ansi_csi = "#{(0x1B).chr}["
40
+ formats = {}
41
+ FORMAT_CODES.each do |name, code|
42
+ formats[name] = code if @properties[name]
43
+ end
44
+ formats[:color] = "3#{COLORS[@properties[:color]]}" if @properties[:color]
45
+ "#{ansi_csi}#{formats.values.join(';')}m#{self}#{ansi_csi}m"
46
+ end
47
+
48
+ def make_colorized(color)
49
+ @properties ||= {}
50
+ @properties[:color] = color
51
+ ansi_formatted
52
+ end
53
+
54
+ COLORS.each do |color,v|
55
+
56
+ define_method color do
57
+ make_colorized(color)
58
+ end
59
+ end
60
+
61
+ FORMAT_CODES.each do |name, code|
62
+
63
+ define_method name do
64
+ @properties ||={}
65
+ @properties[name] = true
66
+ ansi_formatted
67
+ end
68
+ end
69
+ end
70
+
@@ -0,0 +1,249 @@
1
+ module Candelabra
2
+ # This module handles the installing of pianobar Candelabra
3
+ # will support two different ways of installing
4
+ # First is via osx # => brew
5
+ # Second is ubuntu # => apt-get
6
+ #
7
+ # It will also know if pianobar is installed. Because
8
+ # packagemanagers are a good thing Candelabra will allow the
9
+ # packagemanage handle all the hard work with keeping the
10
+ # version correct
11
+ #
12
+ # For Example:
13
+ # Candelabra::Installer.install 'pianobar'
14
+ # # => brew install pianobar
15
+ # # => sudo apt-get install pianobar
16
+ module Installer
17
+ module_function
18
+
19
+ CONSOLE_WIDTH = 70
20
+
21
+ extend OSX
22
+ extend Ubuntu
23
+
24
+ # Executing the installing process.
25
+ def run
26
+ Pianobar.stop_all # make sure all are off
27
+ header
28
+ what_is_installed?
29
+ install_pianobar
30
+ setup_config_file
31
+ make_fifos
32
+ setup_auto_play_station
33
+ end
34
+
35
+ def header
36
+ puts get_template 'header'
37
+ end
38
+
39
+ # Display what is installed to the user
40
+ #
41
+ # Return if all is ok to install
42
+ def what_is_installed?
43
+ which_os = os.green
44
+ package_manager = ( has_installer? ? 'Yes'.green : 'No'.red.blink )
45
+ exe_installed = ( pianobar? ? 'Yes'.green : 'No'.red.blink )
46
+ ctl_file = ( ctl? ? 'Yes'.green : 'No'.red.blink )
47
+ has_notifier = ( notify? ? 'Yes'.green : 'No'.red.blink )
48
+ ok = ( has_installer? ? 'Yes'.green : 'No'.red.blink )
49
+
50
+ puts get_template 'what_is_installed', binding
51
+
52
+ has_installer?
53
+ end
54
+
55
+ def setup_config_file
56
+ puts get_template 'setup_config_file'
57
+ @username, @password = ask( "Enter username:" ), ask( "Enter password:", false )
58
+ write_config_file
59
+ end
60
+
61
+ def write_config_file( station = nil )
62
+ FileUtils.mkdir_p piano_path
63
+ FileUtils.mv config_path, backup_config_name if File.exists? config_path
64
+ File.open( config_path, 'w' ) do |f|
65
+ f.write config_template( station )
66
+ end
67
+ end
68
+
69
+ def make_fifos
70
+ mkfifo( ctl_path ) unless ctl?
71
+ mkfifo( output_path ) unless output?
72
+ mkfifo( input_path ) unless input?
73
+ end
74
+
75
+
76
+ def backup_config_name
77
+ [config_path, @username, Dir.glob(config_path + '*').size.to_s].join('.')
78
+ end
79
+
80
+ def config_template( station_id = nil )
81
+ exe_path = "#{File.dirname(__FILE__)}/../../bin/candelabra"
82
+ station = station_id
83
+ get_template('config', binding)
84
+ end
85
+
86
+ def get_template( name, this_binding = nil )
87
+ erb = ERB.new(File.read(File.dirname(__FILE__) + "/templates/#{name}.erb"))
88
+ erb.result this_binding
89
+ end
90
+
91
+ def start_pianobar
92
+ if Pianobar.running?
93
+ print "Restarting Pianobar with Autostation".ljust(CONSOLE_WIDTH + 20, '.')
94
+ Pianobar.restart
95
+ else
96
+ print "Starting Pianobar".ljust(CONSOLE_WIDTH - 5, '.')
97
+ Pianobar.start
98
+ end
99
+
100
+ 5.times do
101
+ sleep(1)
102
+ putc '.'
103
+ end
104
+
105
+ print Pianobar.running? ? "SUCCESS".green : "FAILED".red.blink
106
+ puts ""
107
+ end
108
+
109
+ def setup_auto_play_station
110
+ puts "Testing Configuration".center(CONSOLE_WIDTH + 20)
111
+ start_pianobar
112
+
113
+
114
+ if Pianobar.running?
115
+ `echo '0' > #{Installer.input_path}` # forcing auto selection of the first station
116
+ sleep( 2 )
117
+ puts ''
118
+ puts "Select Auto station".center( CONSOLE_WIDTH + 20, ' ' )
119
+ stations = Remote.stations
120
+ stations.each { |s| puts s }
121
+
122
+ begin
123
+ result = ask 'Select Station and press ENTER:'
124
+ raise "You must enter the number of a valid station" unless result == result.to_i.to_s
125
+ raise "That is not a valid station it must be a number between 0 and #{stations.size - 1}" unless (0..stations.size - 1).include? result.to_i
126
+ puts "You selected: #{stations[result.to_i]}"
127
+ rescue RuntimeError => e
128
+ puts e.message.red
129
+ puts "You Entered: #{result.red}"
130
+ puts "Try again"
131
+ retry
132
+ end
133
+
134
+ Remote.change_station result
135
+
136
+ write_config_file( Remote.station_id )
137
+
138
+ start_pianobar
139
+ end
140
+ end
141
+
142
+ # Instal
143
+ def install_pianobar
144
+ print "Installing Pianobar".ljust(CONSOLE_WIDTH, '.')
145
+ install 'pianobar' unless pianobar?
146
+ print pianobar? ? 'SUCCESS'.green : 'FAILED'.red.blink
147
+ end
148
+
149
+ alias update_pianobar install_pianobar
150
+
151
+ # Helper for asking a question
152
+ #
153
+ # Params:
154
+ # question => the question u want to ask maybe?
155
+ # visiable => this will determine if the output should be
156
+ # displayed or not
157
+ #
158
+ # Returns result of the user's input
159
+ def ask( question, visiable=true )
160
+ begin
161
+ `stty echo`
162
+ print question
163
+ `stty -echo` unless visiable
164
+ gets.chomp
165
+ ensure
166
+ `stty echo`
167
+ end
168
+ end
169
+
170
+
171
+ # Checking to determine if pianobar is installed it is just
172
+ # looking for the executable.
173
+ #
174
+ # Example:
175
+ # Candelabra::Install.pianobar?
176
+ # # => true if pianobar is in the path
177
+ #
178
+ # Returns true when pianobar is installed
179
+ def pianobar?
180
+ !pianobar_path.empty?
181
+ end
182
+
183
+ # Gets the path to pianobar. If it's installed on the system
184
+ # and in your path it will be located. This path is what is
185
+ # used to determine if pianobar needs to be installed
186
+ #
187
+ # Example:
188
+ # Candelabra::Installer.pianobar_path
189
+ # # => /usr/local/bin/pianobar
190
+ #
191
+ # Returns a string
192
+ def pianobar_path
193
+ %x[which pianobar]
194
+ end
195
+
196
+
197
+ # Util method. Should be moved to the install module when it
198
+ # has been created.
199
+ #
200
+ # Example:
201
+ # Candelabra::Pianobar.make_logs
202
+ # # => doesn't really belong here
203
+ #
204
+ # Returns nothing. but it makes the logs dir
205
+ def mkfifo( path )
206
+ %x[mkfifo "#{path}"]
207
+ end
208
+
209
+ def output?
210
+ test ?p, output_path
211
+ end
212
+
213
+ def input?
214
+ test ?p, input_path
215
+ end
216
+
217
+ # Pianobar can talk to a remote file. This will determin if
218
+ # the file is setup.
219
+ #
220
+ # Returns true when setup in the expected location
221
+ def ctl?
222
+ test ?p, ctl_path
223
+ end
224
+
225
+ def piano_path
226
+ "#{ENV['HOME']}/.config/pianobar"
227
+ end
228
+
229
+ def config_path
230
+ "#{piano_path}/config"
231
+ end
232
+
233
+ def output_path
234
+ "#{piano_path}/output.fifo"
235
+ end
236
+
237
+ def input_path
238
+ "#{piano_path}/input.fifo"
239
+ end
240
+
241
+ # The path of the control file. This file must be a fifo file
242
+ # inorder for it to be the correct ctl file.
243
+ #
244
+ # Returns the path to the control file
245
+ def ctl_path
246
+ "#{piano_path}/ctl"
247
+ end
248
+ end
249
+ end
@@ -0,0 +1,88 @@
1
+ module Candelabra
2
+ # This module contains installer specific instructions for OSX
3
+ # using home bree Home brew is the best package manager for OSX
4
+ # right now and the package manager that is going to be
5
+ # supported. Include this module into your class/module and you
6
+ # will be able to install using home brew.
7
+ #
8
+ # NOTE: This module will only be active if the os is OSX
9
+ module OSX
10
+ module InstanceMethods
11
+ # Installs the requested package using home brew. If the
12
+ # package is already installed home brew will not install
13
+ # it
14
+ #
15
+ # Example:
16
+ # Candelabra::Install.install 'pianobar'
17
+ # # => brew installs pianobar
18
+ #
19
+ # Returns standard output from home brew
20
+ def install lib
21
+ %x[brew install #{lib}] if has_installer?
22
+ end
23
+
24
+ # Gets the path of home brew. If it's somewere on your
25
+ # system this finds it. Candelabra assumes that you don't
26
+ # use sudo to install the brew packages
27
+ #
28
+ # Example:
29
+ # Candelabra::Install.brew_path
30
+ # # => /usr/local/bin/brew
31
+ #
32
+ # Returns a string
33
+ def installer_path
34
+ %x[which brew].chomp
35
+ end
36
+
37
+ # Simple check to determine if home brew is installed
38
+ #
39
+ # Example:
40
+ # Candelabra::Install.has_installer?
41
+ # # => On osx it should be true
42
+ # # => On ubuntu it should be false
43
+ #
44
+ # Returns true if home brew is there
45
+ def has_installer?
46
+ !installer_path.nil?
47
+ end
48
+
49
+ def os
50
+ 'OSX'
51
+ end
52
+
53
+ def notify?
54
+ !%x[which growlnotify].chomp.nil?
55
+ end
56
+
57
+ # Notify the user using growl
58
+ def notify
59
+ %x[growlnotify --image #{art_work} -t "Pianobar - #{stationName}" -m "Now Playing: #{artist} - #{title}"]
60
+ end
61
+
62
+ end
63
+
64
+ # Load the installer methods IF this is the correct OS
65
+ def self.extended klass
66
+ klass.extend( InstanceMethods ) if osx?
67
+ end
68
+
69
+ # Load the installer methods IF this is the correct OS
70
+ def self.included klass
71
+ klass.send( :include, InstanceMethods ) if osx?
72
+ end
73
+
74
+ # This method will say if the OS is OSX or not
75
+ #
76
+ # Example:
77
+ # [ On OSX ] osx?
78
+ # # => true
79
+ #
80
+ # [ On Linux ] osx?
81
+ # # => false
82
+ #
83
+ # Returns true for OSX
84
+ def self.osx?
85
+ !( /darwin/ =~ RbConfig::CONFIG["target_os"] ).nil?
86
+ end
87
+ end
88
+ end