dhun 0.5.6 → 0.6.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/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
|