class Subcl
Constants
- PLAYER_METHODS
these methods will be passed through to the underlying player
- VERSION
Attributes
api[RW]
configs[RW]
notifier[RW]
player[RW]
Public Class Methods
new(options = {})
click to toggle source
# File lib/subcl/subcl.rb, line 5 def initialize(options = {}) #TODO merge options and configs @options = { :interactive => true, :tty => true, :insert => false, :out_stream => STDOUT, :err_stream => STDERR, :wildcard_order => %i{playlist album artist song} }.merge! options @out = @options[:out_stream] @err = @options[:err_stream] begin @configs = Configs.new rescue => e @err.puts "Error initializing config" @err.puts e.message exit 4 end @configs[:random_song_count] = @options[:random_song_count] if @options[:random_song_count] @player = @options[:mock_player] || Player.new @api = @options[:mock_api] || SubsonicAPI.new(@configs) @notifier = Notify.new @configs[:notify_method] @display = { :song => proc { |song| @out.puts sprintf "%-20.20s %-20.20s %-20.20s %-4.4s", song[:title], song[:artist], song[:album], song[:year] }, :album => proc { |album| @out.puts sprintf "%-30.30s %-30.30s %-4.4s", album[:name], album[:artist], album[:year] }, :artist => proc { |artist| @out.puts "#{artist[:name]}" }, :playlist => proc { |playlist| @out.puts "#{playlist[:name]} by #{playlist[:owner]}" }, :any => proc { |thing| #TODO this works, but looks confusing when multiple types are displayed @display[thing[:type]].call(thing) } } end
Public Instance Methods
albumart_url(size = nil)
click to toggle source
# File lib/subcl/subcl.rb, line 55 def albumart_url(size = nil) current = @player.current_song @api.albumart_url(current.file, size) if current end
albumlist()
click to toggle source
# File lib/subcl/subcl.rb, line 163 def albumlist @api.albumlist.each do |album| @display[:album].call(album) end end
any_sorter(query)
click to toggle source
returns a sorter proc for two hashes with the attribute :type and :name
it will use split(“ ”) on query and then count how many words of query each :name contains. If two hashes have the same amount of query words, @options is used
the closest matches will be at the beginning
# File lib/subcl/subcl.rb, line 115 def any_sorter(query) #TODO do things with query! find the things that match the query the most order = @options[:wildcard_order] lambda do |e1, e2| cmp = match_score(e1, query) <=> match_score(e2, query) if cmp == 0 out = order.index(e1[:type]) <=> order.index(e2[:type]) out else -cmp end end end
invoke_picker(array, &display_proc)
click to toggle source
show an interactive picker that lists every element of the array using &display_proc The user can then choose one, many or no of the elements which will be returned as array
# File lib/subcl/subcl.rb, line 171 def invoke_picker(array, &display_proc) return array if array.length <= 1 return [array.first] unless @options[:interactive] return Picker.new(array).pick(&display_proc) end
match_score(entity, query)
click to toggle source
# File lib/subcl/subcl.rb, line 129 def match_score(entity, query) query.split(' ').inject(0) do |memo, word| memo + (entity[:name].downcase.include?(word.downcase) ? 1 : 0) end end
method_missing(name, args)
click to toggle source
# File lib/subcl/subcl.rb, line 179 def method_missing(name, args) raise NoMethodError unless PLAYER_METHODS.include? name @player.send(name) end
no_matches(what = nil)
click to toggle source
print an error that no matches were found, then exit with code 2
# File lib/subcl/subcl.rb, line 144 def no_matches(what = nil) if what message = "No matching #{what}" else message = "No matches" end if @options[:tty] @err.puts message else @notifier.notify(message) end exit 2 end
print(name, type)
click to toggle source
# File lib/subcl/subcl.rb, line 135 def print(name, type) entities = @api.search(name, type) no_matches(type) if entities.empty? entities.each do |entity| @display[type].call(entity) end end
queue(query, type, inArgs = {})
click to toggle source
# File lib/subcl/subcl.rb, line 60 def queue(query, type, inArgs = {}) args = { :clear => false, #whether to clear the playlist prior to adding songs :play => false, #whether to start the player after adding the songs :insert => false #whether to insert the songs after the current instead of the last one } args.merge! inArgs if @options[:current] query = case type when :album @player.current_song.album when :artist @player.current_song.artist else raise ArgumentError, "'current' option can only be used with albums or artists." end end songs = case type when :randomSong begin count = query.empty? ? @configs[:random_song_count] : query @api.random_songs(count) rescue ArgumentError raise ArgumentError, "random-songs takes an integer as argument" end else #song, album, artist, playlist, any entities = @api.search(query, type) entities.sort!(&any_sorter(query)) if type == :any entities = invoke_picker(entities, &@display[type]) @api.get_songs(entities) end no_matches if songs.empty? @player.clearstop if args[:clear] songs.shuffle! if @options[:shuffle] songs.each do |song| @player.add(song, args[:insert]) end @player.play if args[:play] end
testNotify()
click to toggle source
# File lib/subcl/subcl.rb, line 159 def testNotify @notifier.notify("Hi!") end