dhun 0.5.6 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CONTRIBUTORS +1 -0
- data/FIX.md +4 -3
- data/README.md +106 -54
- data/Rakefile +12 -0
- data/TODO.md +0 -9
- data/bin/dhun +2 -1
- data/dhun.gemspec +7 -5
- data/lib/dhun.rb +2 -3
- data/lib/dhun/client.rb +25 -0
- data/lib/dhun/dhun_server.rb +56 -23
- data/lib/dhun/handler.rb +69 -90
- data/lib/dhun/player.rb +90 -65
- data/lib/dhun/query.rb +63 -42
- data/lib/dhun/result.rb +8 -8
- data/lib/dhun/runner.rb +204 -86
- data/lib/dhun/server.rb +6 -48
- metadata +34 -5
- data/lib/dhun/command.rb +0 -15
- data/lib/dhun/controller.rb +0 -160
- data/lib/dhun/dhun_client.rb +0 -30
data/lib/dhun/player.rb
CHANGED
@@ -4,112 +4,137 @@ module Dhun
|
|
4
4
|
class Player
|
5
5
|
include Singleton
|
6
6
|
|
7
|
-
|
8
|
-
attr_reader :history
|
9
|
-
attr_reader :status
|
10
|
-
attr_reader :current
|
11
|
-
|
12
|
-
attr_reader :logger
|
7
|
+
attr_accessor :queue,:history,:status,:current,:logger
|
13
8
|
|
14
9
|
def initialize
|
15
|
-
@queue = []
|
16
|
-
@history = []
|
10
|
+
@queue,@history = [],[]
|
17
11
|
@logger = Logger.instance
|
18
12
|
@status = :stopped
|
19
13
|
end
|
20
14
|
|
21
|
-
|
22
|
-
stop
|
23
|
-
@queue.clear
|
24
|
-
end
|
25
|
-
|
26
|
-
|
27
|
-
def play_files(files)
|
28
|
-
if files.empty?
|
29
|
-
logger.log "Empty Queue"
|
30
|
-
else
|
31
|
-
stop
|
32
|
-
empty_queue
|
33
|
-
files.each { |f| self.queue.push f }
|
34
|
-
play
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
15
|
+
# enqueue files and call play.
|
38
16
|
def enqueue(files)
|
39
|
-
|
40
|
-
play
|
17
|
+
return false if files.empty?
|
18
|
+
files.each { |f| self.queue.push f }; play
|
19
|
+
return true
|
20
|
+
end
|
21
|
+
|
22
|
+
# clear the queue and stops playback
|
23
|
+
def clear
|
24
|
+
stop ; @queue.clear
|
25
|
+
return true
|
41
26
|
end
|
42
27
|
|
28
|
+
# commence playback
|
43
29
|
def play
|
44
|
-
return
|
30
|
+
return :empty if @queue.empty?
|
31
|
+
return false if @status == :playing
|
32
|
+
return resume if @status == :paused
|
45
33
|
@status = :playing
|
46
|
-
@player_thread =
|
47
|
-
|
48
|
-
@current = @queue.shift
|
49
|
-
logger.log "Playing #{@current}"
|
50
|
-
DhunExt.play_file @current
|
51
|
-
@history.unshift @current
|
52
|
-
end
|
53
|
-
@status = :stopped
|
54
|
-
@current = nil
|
55
|
-
end
|
34
|
+
@player_thread = play_thread
|
35
|
+
return true
|
56
36
|
end
|
57
37
|
|
38
|
+
# pause playback
|
39
|
+
# only on :playing
|
58
40
|
def pause
|
59
41
|
if @status == :playing
|
60
42
|
@status = :paused
|
61
43
|
DhunExt.pause
|
44
|
+
@logger.debug "pause"
|
45
|
+
return true
|
62
46
|
end
|
47
|
+
return false
|
63
48
|
end
|
64
49
|
|
50
|
+
# resume playback
|
51
|
+
# only on :paused
|
65
52
|
def resume
|
66
53
|
if @status == :paused
|
67
54
|
@status = :playing
|
68
55
|
DhunExt.resume
|
56
|
+
@logger.debug "resume"
|
57
|
+
return true
|
69
58
|
end
|
59
|
+
return false
|
70
60
|
end
|
71
61
|
|
62
|
+
# stops the song
|
63
|
+
# unless :stopped
|
72
64
|
def stop
|
73
|
-
@status
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
65
|
+
unless @status == :stopped
|
66
|
+
@status = :stopped
|
67
|
+
DhunExt.stop
|
68
|
+
# Wait for @player_thread to exit cleanly
|
69
|
+
@player_thread.join unless @player_thread.nil?
|
70
|
+
@logger.debug "Stopped"
|
71
|
+
return true
|
72
|
+
end
|
73
|
+
return false
|
78
74
|
end
|
79
75
|
|
76
|
+
# plays next song on queue.
|
77
|
+
# returns next_track or false if invalid
|
80
78
|
def next(skip_length = 1)
|
81
|
-
|
82
|
-
|
83
|
-
stop
|
84
|
-
@queue.shift
|
79
|
+
unless skip_length > @queue.size
|
80
|
+
@logger.debug "next invoked"
|
81
|
+
stop
|
82
|
+
@queue.shift(skip_length - 1) #skip_length returns starting with first on queue.
|
85
83
|
next_track = @queue.first
|
86
|
-
play
|
84
|
+
play
|
85
|
+
return next_track
|
87
86
|
end
|
88
|
-
return
|
87
|
+
return false
|
89
88
|
end
|
90
89
|
|
90
|
+
# when :stopped
|
91
|
+
# returns the first song in history
|
92
|
+
# when :playing
|
93
|
+
# returns the second song in history as first song is current song
|
91
94
|
def prev(skip_length = 1)
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
end
|
95
|
+
# skip current track if playing
|
96
|
+
if @status == :playing
|
97
|
+
stop ; skip_length += 1
|
98
|
+
end
|
99
|
+
unless skip_length > @history.size
|
100
|
+
@logger.debug "previous invoked"
|
99
101
|
tracks = @history.shift skip_length
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
102
|
+
tracks.each { |track| @queue.unshift track }
|
103
|
+
previous = @queue.first
|
104
|
+
play
|
105
|
+
return previous
|
104
106
|
end
|
105
|
-
return
|
107
|
+
return false
|
106
108
|
end
|
107
109
|
|
110
|
+
# shuffle queue if queue is not empty
|
111
|
+
# ensures that shuffled queue is not equal to previous queue order
|
112
|
+
# NOTE: if they enqueue all the same songs, this will NOT end. should catch that.
|
108
113
|
def shuffle
|
109
|
-
return if @queue.empty?
|
110
|
-
|
111
|
-
|
112
|
-
|
114
|
+
return false if @queue.empty? or @queue.uniq.size == 1 # this will catch a playlist of same songs
|
115
|
+
q = @queue.clone
|
116
|
+
while q == @queue
|
117
|
+
@queue.size.downto(1) { |n| @queue.push @queue.delete_at(rand(n)) }
|
118
|
+
end
|
119
|
+
@logger.debug @queue
|
120
|
+
return true
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
# play method's player thread
|
126
|
+
def play_thread
|
127
|
+
Thread.new do
|
128
|
+
while @status == :playing and !@queue.empty?
|
129
|
+
@current = @queue.shift
|
130
|
+
@logger.log "Playing #{@current}"
|
131
|
+
DhunExt.play_file @current
|
132
|
+
@history.unshift @current
|
133
|
+
end
|
134
|
+
@status = :stopped
|
135
|
+
@current = nil
|
136
|
+
end
|
113
137
|
end
|
138
|
+
|
114
139
|
end
|
115
140
|
end
|
data/lib/dhun/query.rb
CHANGED
@@ -3,64 +3,85 @@ require 'dhun_ext'
|
|
3
3
|
module Dhun
|
4
4
|
class Query
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
MAPPINGS = {
|
7
|
+
:file => :kMDItemFSName,
|
8
|
+
:album => :kMDItemAlbum,
|
9
|
+
:artist => :kMDItemAuthors,
|
10
|
+
:title => :kMDItemTitle,
|
11
|
+
:genre => :kMDItemMusicalGenre,
|
12
|
+
:composer => :kMDItemComposer,
|
13
|
+
:display => :kMDItemDisplayName
|
14
|
+
}
|
8
15
|
|
9
|
-
|
16
|
+
attr_accessor :spotlight_query,:is_valid,:logger,:query_search,:query_fields
|
10
17
|
|
11
|
-
def initialize(
|
12
|
-
@
|
13
|
-
|
18
|
+
def initialize(search=nil,fields={})
|
19
|
+
@logger = Dhun::Logger.instance
|
20
|
+
@query_search = search
|
21
|
+
@query_fields = fields
|
22
|
+
@is_valid = parse!
|
14
23
|
end
|
15
24
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
25
|
+
# parses all search terms and stores query
|
26
|
+
# return false if both are empty.
|
27
|
+
def parse!
|
28
|
+
return false if @query_search.nil? and @query_fields.empty?
|
20
29
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
strings.push(arg)
|
27
|
-
end
|
28
|
-
end
|
30
|
+
mappings = MAPPINGS.values #instantiate mappings to be picked off by query methods
|
31
|
+
#create the queries
|
32
|
+
filter_query = create_filter_query(@query_fields,mappings)
|
33
|
+
string_query = create_string_query(@query_search,mappings)
|
34
|
+
@spotlight_query = create_spotlight_query(filter_query,string_query)
|
29
35
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
md_item = MAPPINGS[fltr]
|
34
|
-
mappings.delete md_item
|
35
|
-
"#{md_item} == '#{query.strip}'wc"
|
36
|
-
end.join(" && ")
|
37
|
-
|
38
|
-
|
39
|
-
template = "%s == '%s'wc"
|
40
|
-
sq = strings.collect do |keyword|
|
41
|
-
q = mappings.collect { |key| template % [key,keyword] }.join(" || ")
|
42
|
-
"( #{q} )"
|
43
|
-
end.join(" && ")
|
36
|
+
@logger.debug @spotlight_query
|
37
|
+
return true
|
38
|
+
end
|
44
39
|
|
45
|
-
|
46
|
-
|
47
|
-
|
40
|
+
# create filter queries
|
41
|
+
# { :album => 'test' } => "kMDItemAlbum == 'test'wc"
|
42
|
+
# ADDITIONALLY, throws out any non matching filters
|
43
|
+
# { :album => 'test', :booger => 'one' } => "kMDItemAlbum == 'test'wc"
|
44
|
+
def create_filter_query(filters,mappings)
|
45
|
+
filters.collect do |field,value|
|
46
|
+
md_item = MAPPINGS[field.to_sym]
|
47
|
+
next unless md_item # makes sure that field is to sym, or funky stuff happens
|
48
|
+
mappings.delete md_item
|
49
|
+
"#{md_item} == '#{value}'wc && "
|
50
|
+
end.join.chomp(" && ")
|
48
51
|
end
|
49
52
|
|
50
|
-
|
51
|
-
|
53
|
+
# create string queries
|
54
|
+
# this sets string to all fields not already matched
|
55
|
+
# by create_filter_query
|
56
|
+
# 'test' => "( kMDItemTitle == 'holy'wc || kMDItemMusicalGenre == 'holy'wc )"
|
57
|
+
# if kMDItemTitle and kMDItemMusicalGenre are the only fields left open.
|
58
|
+
# returns "" if given nil
|
59
|
+
# if given multiple strings:
|
60
|
+
# 'holy','test' =>
|
61
|
+
# ( kMDItemTitle == 'holy'wc || kMDItemMusicalGenre == 'holy'wc ) && ( kMDItemTitle == 'test'wc || kMDItemMusicalGenre == 'test'wc )
|
62
|
+
def create_string_query(strings,mappings)
|
63
|
+
return "" unless strings
|
64
|
+
strings.collect do |keyword|
|
65
|
+
query = mappings.collect { |key| "%s == '%s'wc" % [key,keyword] }.join(" || ")
|
66
|
+
"( #{query} )"
|
67
|
+
end.join(" && ")
|
52
68
|
end
|
53
69
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
70
|
+
# create spotlight queries
|
71
|
+
# with {:album => 'test'},"" =>
|
72
|
+
# "kMDItemContentTypeTree == 'public.audio' && kMDItemAlbum == 'test'wc"
|
73
|
+
def create_spotlight_query(filter_query,string_query)
|
74
|
+
["kMDItemContentTypeTree == 'public.audio'", filter_query, string_query].select do |s|
|
75
|
+
s.length > 0
|
76
|
+
end.join(" && ")
|
59
77
|
end
|
60
78
|
|
61
79
|
# Use extension to query spotlight
|
62
80
|
def execute_spotlight_query
|
63
81
|
return DhunExt.query_spotlight(@spotlight_query)
|
64
82
|
end
|
83
|
+
|
84
|
+
def is_valid?; @is_valid; end
|
85
|
+
|
65
86
|
end
|
66
87
|
end
|
data/lib/dhun/result.rb
CHANGED
@@ -1,31 +1,31 @@
|
|
1
1
|
require 'json'
|
2
2
|
module Dhun
|
3
3
|
class Result
|
4
|
+
attr_reader :data
|
4
5
|
|
5
6
|
def initialize(result, message, options = {})
|
6
|
-
@
|
7
|
-
@response.merge!(options)
|
7
|
+
@data = { :result => result.to_sym, :message => message }.merge(options)
|
8
8
|
end
|
9
9
|
|
10
10
|
def success?
|
11
|
-
@
|
11
|
+
@data[:result] == :success
|
12
12
|
end
|
13
13
|
|
14
14
|
def error?
|
15
|
-
@
|
15
|
+
@data[:result] == :error
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
def [](sym)
|
19
|
-
@
|
19
|
+
@data[sym.to_sym] || @data[sym.to_s]
|
20
20
|
end
|
21
21
|
|
22
22
|
def to_json
|
23
|
-
@
|
23
|
+
@data.to_json
|
24
24
|
end
|
25
25
|
|
26
26
|
def self.from_json_str(resp_json)
|
27
27
|
resp = JSON.parse(resp_json)
|
28
|
-
Result.new(
|
28
|
+
Result.new resp.delete('result'), resp.delete('message'), resp
|
29
29
|
end
|
30
30
|
|
31
31
|
end
|
data/lib/dhun/runner.rb
CHANGED
@@ -1,104 +1,222 @@
|
|
1
|
-
require '
|
1
|
+
require 'thor'
|
2
|
+
require 'json'
|
2
3
|
|
3
4
|
module Dhun
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
CLIENT_COMMANDS = %w(stop play pause resume next prev enqueue status shuffle history)
|
9
|
-
# Parsed options
|
10
|
-
attr_accessor :options
|
11
|
-
|
12
|
-
# Name of the command to be runned.
|
13
|
-
attr_accessor :command
|
14
|
-
|
15
|
-
# Arguments to be passed to the command.
|
16
|
-
attr_accessor :arguments
|
17
|
-
|
18
|
-
# Return all available commands
|
19
|
-
def self.commands
|
20
|
-
commands = COMMANDS + CLIENT_COMMANDS
|
21
|
-
commands
|
22
|
-
end
|
23
|
-
|
24
|
-
def initialize(argv)
|
25
|
-
@argv = argv
|
26
|
-
# Default options values
|
27
|
-
@options = {
|
28
|
-
:socket => "/tmp/dhun.sock",
|
29
|
-
:default_log => "/tmp/dhun.log"
|
30
|
-
}
|
31
|
-
parse!
|
32
|
-
end
|
33
|
-
|
34
|
-
def parser
|
35
|
-
# NOTE: If you add an option here make sure the key in the +options+ hash is the
|
36
|
-
# same as the name of the command line option.
|
37
|
-
# +option+ keys are used to build the command line to launch other processes,
|
38
|
-
# see <tt>lib/dhun/command.rb</tt>.
|
39
|
-
@parser ||= OptionParser.new do |opts|
|
40
|
-
opts.banner = <<-EOF
|
41
|
-
Usage:
|
42
|
-
dhun start
|
43
|
-
dhun play spirit
|
44
|
-
dhun pause
|
45
|
-
dhun resume
|
46
|
-
dhun enqueue rahman
|
47
|
-
dhun status
|
48
|
-
dhun shuffle
|
49
|
-
dhun stop
|
50
|
-
|
51
|
-
For more details see README at http://github.com/deepakjois/dhun
|
52
|
-
EOF
|
53
|
-
opts.separator ""
|
54
|
-
opts.on("-d", "--daemonize", "Run daemonized in the background") { @options[:daemonize] = true }
|
55
|
-
opts.on("-l", "--log FILE", "File to redirect output " +
|
56
|
-
"(default: #{@options[:default_log]})") { |file| @options[:log] = file }
|
57
|
-
|
58
|
-
opts.separator "Common options:"
|
59
|
-
opts.on_tail("-h", "--help", "Show this message") { puts opts; exit }
|
60
|
-
opts.on_tail("-D", "--debug", "Set debugging on") { @options[:debug] = true }
|
61
|
-
opts.on_tail("-h", "--help", "Show this message") { puts opts; exit }
|
62
|
-
opts.on_tail('-v', '--version', "Show version") { puts "Dhun " + Dhun::VERSION; exit }
|
6
|
+
class Runner < Thor
|
7
|
+
include Thor::Actions
|
8
|
+
include Dhun::Client
|
63
9
|
|
10
|
+
def self.banner(task)
|
11
|
+
task.formatted_usage(self).gsub("dhun:runner:","dhun ")
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "start_server","Starts the Dhun Server."
|
15
|
+
method_option :socket, :type => :string, :default => "/tmp/dhun.sock", :aliases => '-s'
|
16
|
+
method_option :log, :type => :string, :default => "/tmp/dhun.log", :aliases => '-l'
|
17
|
+
method_option :foreground, :type => :boolean, :default => false, :aliases => '-f'
|
18
|
+
method_option :debug, :type => :boolean, :default => false, :aliases => '-D'
|
19
|
+
def start_server
|
20
|
+
unless server_running?(options[:socket],:silent)
|
21
|
+
server_path = File.join File.dirname(__FILE__), 'server.rb'
|
22
|
+
cmd = options[:foreground] ? 'run' : 'start'
|
23
|
+
say "Starting Dhun", :green
|
24
|
+
system("ruby #{server_path} #{cmd} -- #{options[:socket]} #{options[:log]}")
|
25
|
+
else
|
26
|
+
say "Dhun Server is already running", :yellow
|
64
27
|
end
|
65
28
|
end
|
66
29
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
30
|
+
desc "stop_server","Stop the Dhun Server"
|
31
|
+
def stop_server
|
32
|
+
server_path = File.join File.dirname(__FILE__), 'server.rb'
|
33
|
+
system("ruby #{server_path} stop")
|
34
|
+
say "Stopping Dhun", :green
|
71
35
|
end
|
72
36
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
37
|
+
desc "query SEARCH","Show files matching query. ex: dhun query bob,'the marley'
|
38
|
+
\t\t\t See docs for details on query syntax"
|
39
|
+
method_option :artist, :type => :string, :aliases => '-a'
|
40
|
+
method_option :album, :type => :string, :aliases => '-l'
|
41
|
+
method_option :genre, :type => :string, :aliases => '-g'
|
42
|
+
method_option :file, :type => :string, :aliases => '-f'
|
43
|
+
method_option :title, :type => :string, :aliases => '-t'
|
44
|
+
def query(search=nil)
|
45
|
+
search = search.nil? ? nil : search.split(',')
|
46
|
+
query = Dhun::Query.new(search,options)
|
47
|
+
if query.is_valid?
|
48
|
+
|
49
|
+
#make the prompt pretty. i think.
|
50
|
+
opts = options.collect {|field,value| "#{field}:#{value}" }.join(" ")
|
51
|
+
term = search.nil? ? '[nil]' : search.join(",")
|
52
|
+
say "Querying: #{term} | #{opts}", :cyan
|
53
|
+
|
54
|
+
# commence the query, and respond as so.
|
55
|
+
files = query.execute_spotlight_query
|
56
|
+
if files.empty?
|
57
|
+
say "No Results Found", :red
|
58
|
+
else
|
59
|
+
say "#{files.size} Results", :green
|
60
|
+
say_list files
|
84
61
|
end
|
85
|
-
run_command
|
86
|
-
elsif @command.nil?
|
87
|
-
puts "Command required"
|
88
|
-
puts @parser
|
89
|
-
exit 1
|
90
62
|
else
|
91
|
-
|
63
|
+
say "Invalid Query Syntax. See docs for correct syntax", :yellow
|
64
|
+
end
|
65
|
+
files
|
66
|
+
end
|
67
|
+
|
68
|
+
desc "play SEARCH","Play songs matching query. ex: dhun play bob,'the marley'
|
69
|
+
\t\t\t See docs for details on query syntax"
|
70
|
+
method_option :artist, :type => :string, :aliases => '-a'
|
71
|
+
method_option :album, :type => :string, :aliases => '-l'
|
72
|
+
method_option :genre, :type => :string, :aliases => '-g'
|
73
|
+
method_option :file, :type => :string, :aliases => '-f'
|
74
|
+
method_option :title, :type => :string, :aliases => '-t'
|
75
|
+
def play(search=nil)
|
76
|
+
return return_response(:play,[]) if search.nil? and options.empty?
|
77
|
+
return_response(:clear,[])
|
78
|
+
invoke :enqueue, [search], options
|
79
|
+
end
|
80
|
+
|
81
|
+
desc "enqueue SEARCH","Enqueue songs matching query. ex: dhun enqueue bob,'the marley'
|
82
|
+
\t\t\t See docs for details on query syntax"
|
83
|
+
method_option :artist, :type => :string, :aliases => '-a'
|
84
|
+
method_option :album, :type => :string, :aliases => '-l'
|
85
|
+
method_option :genre, :type => :string, :aliases => '-g'
|
86
|
+
method_option :file, :type => :string, :aliases => '-f'
|
87
|
+
method_option :title, :type => :string, :aliases => '-t'
|
88
|
+
def enqueue(search=nil)
|
89
|
+
|
90
|
+
# invoke query command and return us all the files found.
|
91
|
+
files = invoke :query, [search], options
|
92
|
+
if files and !files.empty?
|
93
|
+
#prompt for index of song to play and return it in pretty format. cough.
|
94
|
+
if files.size == 1 # Dont prompt if result size is 1
|
95
|
+
indexes = [0]
|
96
|
+
else
|
97
|
+
answer = ask "Enter index to queue (ENTER to select all): ",:yellow
|
98
|
+
|
99
|
+
indexes ||=
|
100
|
+
case
|
101
|
+
when answer.include?(',') then answer.split(',')
|
102
|
+
when answer.include?(' ') then answer.split(' ')
|
103
|
+
when answer.size >= 1 then answer.to_a
|
104
|
+
else
|
105
|
+
0..(files.size - 1)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
selected = indexes.map { |index| files[index.to_i] }
|
109
|
+
say "selected:",:green
|
110
|
+
say_list selected
|
111
|
+
|
112
|
+
return_response(:enqueue,nil,selected)
|
92
113
|
end
|
93
114
|
end
|
94
115
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
116
|
+
desc "next COUNT", "Skips to next song by COUNT"
|
117
|
+
def next(count=1)
|
118
|
+
return_response(:next,[],count.to_i)
|
119
|
+
end
|
120
|
+
|
121
|
+
desc "prev COUNT", "Skips to previous song by COUNT"
|
122
|
+
def prev(count=1)
|
123
|
+
return_response(:prev,[],count.to_i)
|
124
|
+
end
|
125
|
+
|
126
|
+
desc "status", "Shows the status"
|
127
|
+
def status
|
128
|
+
return unless server_running?
|
129
|
+
response = return_response(:status,[:current,:queue])
|
130
|
+
say "Currently Playing:",:magenta
|
131
|
+
say response[:current],:white
|
132
|
+
say "Queue:",:cyan
|
133
|
+
say_list response[:queue]
|
134
|
+
end
|
135
|
+
|
136
|
+
desc "history", "Shows the previously played songs"
|
137
|
+
def history
|
138
|
+
response = return_response(:history,[:history])
|
139
|
+
if response[:history]
|
140
|
+
say "History:",:cyan
|
141
|
+
say_list response[:history]
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
desc "shuffle", "Shuffles the queue"
|
146
|
+
def shuffle
|
147
|
+
response = return_response(:shuffle,[:queue])
|
148
|
+
if response[:queue]
|
149
|
+
say "Queue:",:cyan
|
150
|
+
say_list response[:queue]
|
101
151
|
end
|
102
152
|
end
|
153
|
+
|
154
|
+
desc "pause", "Pauses playing"
|
155
|
+
def pause
|
156
|
+
return_response(:pause,[])
|
157
|
+
end
|
158
|
+
|
159
|
+
desc "resume", "Resumes playing"
|
160
|
+
def resume
|
161
|
+
return_response(:resume,[])
|
162
|
+
end
|
163
|
+
|
164
|
+
desc "stop", "Stops playing"
|
165
|
+
def stop
|
166
|
+
return_response(:stop,[])
|
167
|
+
end
|
168
|
+
|
169
|
+
|
170
|
+
private
|
171
|
+
|
172
|
+
# sends command to dhun client
|
173
|
+
def send_command(command,arguments=[])
|
174
|
+
cmd = { "command" => command.to_s, "arguments" => arguments }.to_json
|
175
|
+
send_message(cmd,"/tmp/dhun.sock")
|
176
|
+
end
|
177
|
+
|
178
|
+
# send command to the server and retrieve response.
|
179
|
+
def get_response(command,arguments=[])
|
180
|
+
if server_running?
|
181
|
+
resp = send_command(command,arguments)
|
182
|
+
return Dhun::Result.from_json_str(resp)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
# prints out list with each index value
|
187
|
+
# in pretty format! (contrasting colors)
|
188
|
+
def say_list(list)
|
189
|
+
list.each_with_index do |item,index|
|
190
|
+
color = index.even? ? :white : :cyan
|
191
|
+
say("#{index} : #{item}",color)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
# check to see if Dhun Server is running.
|
196
|
+
# asks to start Dhun server if not
|
197
|
+
# takes argument :silent to quiet its output.
|
198
|
+
# need to make the socket choices more flexible
|
199
|
+
def server_running?(socket = "/tmp/dhun.sock",verbose = :verbose)
|
200
|
+
socket ||= "/tmp/dhun.sock"
|
201
|
+
if is_server?(socket)
|
202
|
+
return true
|
203
|
+
else
|
204
|
+
say("Please start Dhun server first with : dhun start_server", :red) unless verbose == :silent
|
205
|
+
return false
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
#send out the command to server and see what it has to say.
|
210
|
+
def return_response(action,keys,argument=[])
|
211
|
+
response = get_response(action,argument)
|
212
|
+
if response
|
213
|
+
color = response.success? ? :red : :cyan
|
214
|
+
say response[:message], color
|
215
|
+
if keys
|
216
|
+
return keys.inject({}) {|base,key| base[key.to_sym] = response[key.to_sym] ; base}
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
103
221
|
end
|
104
222
|
end
|