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.
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