dhun 0.5.4 → 0.5.5
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/FIX.md +2 -3
- data/README.md +33 -24
- data/dhun.gemspec +2 -2
- data/lib/dhun.rb +1 -1
- data/lib/dhun/controller.rb +16 -2
- data/lib/dhun/handler.rb +9 -2
- data/lib/dhun/player.rb +5 -1
- data/lib/dhun/query.rb +41 -19
- data/lib/dhun/runner.rb +6 -2
- metadata +2 -2
data/FIX.md
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
## Fixes/Improvements required
|
2
2
|
|
3
|
-
*
|
4
|
-
|
5
|
-
* Maintaining history of all files played in the session
|
3
|
+
* Refactor multiple calls to result.to_json
|
4
|
+
* Refactor handler calls by converting it from module to subclass of EventMachine::Connection object
|
data/README.md
CHANGED
@@ -29,42 +29,53 @@ the `gem` command to compile the native extensions.
|
|
29
29
|
Pass the `-d` option to run the server as a daemon in the background. See
|
30
30
|
`dhun -h` for more options.
|
31
31
|
|
32
|
-
|
32
|
+
|
33
|
+
### Querying for files
|
33
34
|
|
34
35
|
Dhun uses Spotlight to query for music files. Just specify a keyword, and Dhun
|
35
36
|
will look for files matching that keyword and start playing them.
|
36
37
|
|
37
|
-
You can also query the Spotlight database before playing the files
|
38
|
+
You can also query the Spotlight database before playing the files, with the
|
39
|
+
`query` command.
|
38
40
|
|
39
41
|
$ dhun query here
|
40
|
-
|
42
|
+
3 Results
|
41
43
|
/Users/deepak/Music/iTunes/iTunes Media/Music/Edward Sharpe & The Magnetic Zeros/Here Comes/01 40 Day Dream.mp3
|
42
44
|
/Users/deepak/Music/iTunes/iTunes Media/Music/Edward Sharpe & The Magnetic Zeros/Here Comes/02 Janglin.mp3
|
43
45
|
/Users/deepak/Music/iTunes/iTunes Media/Music/Edward Sharpe & The Magnetic Zeros/Here Comes/03 Carries On.mp3
|
44
|
-
/Users/deepak/Music/Amazon MP3/Edward Sharpe & The Magnetic Zeros/Here Comes/01 - 40 Day Dream.mp3
|
45
|
-
/Users/deepak/Music/Amazon MP3/Edward Sharpe & The Magnetic Zeros/Here Comes/02 - Janglin.mp3
|
46
|
-
/Users/deepak/Music/Amazon MP3/Edward Sharpe & The Magnetic Zeros/Here Comes/03 - Carries On.mp3
|
47
|
-
/Users/deepak/Dropbox/shared/music/Here Comes/02 - Janglin.mp3
|
48
|
-
/Users/deepak/Dropbox/shared/music/Here Comes/01 - 40 Day Dream.mp3
|
49
|
-
/Users/deepak/Dropbox/shared/music/Here Comes/03 - Carries On.mp3
|
50
46
|
|
51
|
-
|
52
|
-
|
53
|
-
|
47
|
+
You can use query filters like `album:sid` or `artist:rahman`. Currently
|
48
|
+
`album`, `artist`, `title`, `genre` and `file` filters are supported.
|
49
|
+
|
50
|
+
$ dhun query genre:world album:gypsy
|
51
|
+
5 results
|
52
|
+
/Users/deepak/Dropbox/shared/music/gypsy/Putumayo - Gypsy Groove - 11 - Eastenders - Vino Iubirea Mea (!DelaDap Remix) (Germany).mp3
|
53
|
+
/Users/deepak/Dropbox/shared/music/gypsy/Putumayo - Gypsy Groove - 10 - Luminescent Orchestrii - Amari Szi, Amari (Amon Remix) (USA).mp3
|
54
|
+
/Users/deepak/Dropbox/shared/music/gypsy/Putumayo - Gypsy Groove - 09 - Kistehén Tánczenekar - Virágok a Réten (Romano Drom Remix) (Hungary).mp3
|
55
|
+
/Users/deepak/Dropbox/shared/music/gypsy/Putumayo - Gypsy Groove - 08 - Anselmo Crew - Süt Ictim Dilim Yandi (Hungary).mp3
|
56
|
+
/Users/deepak/Dropbox/shared/music/gypsy/Putumayo - Gypsy Groove - 07 - Magnifico & Turbolentza - Zh Ne Sui Pa Pur Tua (Slovenia).mp3
|
57
|
+
|
58
|
+
You can even mix the filters with a regular query like.
|
59
|
+
|
60
|
+
$ dhun query genre:world album:gypsy Czech
|
61
|
+
2 Results
|
62
|
+
/Users/deepak/Dropbox/shared/music/gypsy/Putumayo - Gypsy Groove - 01 - !DelaDap - Zsa Manca (Czech Republic-Hungary).mp3
|
63
|
+
/Users/deepak/Dropbox/shared/music/gypsy/Putumayo - Gypsy Groove - 03 - Gipsy.cz - Jednou (Czech Republic).mp3
|
64
|
+
|
65
|
+
Note that if you want to pass filters longer than a word, you will need to
|
66
|
+
enclose the argument in double quotes, like `dhun query "artist:akli d"`
|
67
|
+
|
68
|
+
### Playing Files
|
69
|
+
|
70
|
+
When you are ready to play the files, pass the query to the `play` command.
|
71
|
+
Note that the `play` command will remove anything that may be already there on
|
72
|
+
your queue. To append files to queue, use `enqueue`.
|
54
73
|
|
55
74
|
$ dhun play here
|
56
|
-
|
75
|
+
3 files queued for playing
|
57
76
|
/Users/deepak/Music/iTunes/iTunes Media/Music/Edward Sharpe & The Magnetic Zeros/Here Comes/01 40 Day Dream.mp3
|
58
77
|
/Users/deepak/Music/iTunes/iTunes Media/Music/Edward Sharpe & The Magnetic Zeros/Here Comes/02 Janglin.mp3
|
59
78
|
/Users/deepak/Music/iTunes/iTunes Media/Music/Edward Sharpe & The Magnetic Zeros/Here Comes/03 Carries On.mp3
|
60
|
-
/Users/deepak/Music/Amazon MP3/Edward Sharpe & The Magnetic Zeros/Here Comes/01 - 40 Day Dream.mp3
|
61
|
-
/Users/deepak/Music/Amazon MP3/Edward Sharpe & The Magnetic Zeros/Here Comes/02 - Janglin.mp3
|
62
|
-
/Users/deepak/Music/Amazon MP3/Edward Sharpe & The Magnetic Zeros/Here Comes/03 - Carries On.mp3
|
63
|
-
/Users/deepak/Dropbox/shared/music/Here Comes/02 - Janglin.mp3
|
64
|
-
/Users/deepak/Dropbox/shared/music/Here Comes/01 - 40 Day Dream.mp3
|
65
|
-
/Users/deepak/Dropbox/shared/music/Here Comes/03 - Carries On.mp3
|
66
|
-
|
67
|
-
More advanced querying support is coming soon.
|
68
79
|
|
69
80
|
### Controlling Playback
|
70
81
|
|
@@ -97,8 +108,7 @@ Status
|
|
97
108
|
/Users/deepak/Dropbox/shared/music/Here Comes/01 - 40 Day Dream.mp3
|
98
109
|
/Users/deepak/Dropbox/shared/music/Here Comes/03 - Carries On.mp3
|
99
110
|
|
100
|
-
Enqueuing more files.
|
101
|
-
before adding new files.
|
111
|
+
Enqueuing more files.
|
102
112
|
|
103
113
|
$ dhun enqueue chup
|
104
114
|
1 files queued for playing.
|
@@ -116,7 +126,6 @@ These features are planned in the next few releases
|
|
116
126
|
|
117
127
|
* Playing previous song, using something like `dhun prev`
|
118
128
|
* Skipping ahead by more than one file, like `dhun next 2` or `dhun prev 2`
|
119
|
-
* Advanced querying support with filters, like `dhun play "artist:Rahman"`
|
120
129
|
|
121
130
|
And someday..
|
122
131
|
|
data/dhun.gemspec
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'dhun'
|
3
|
-
s.version = '0.5.
|
3
|
+
s.version = '0.5.5'
|
4
4
|
s.summary = "Minimalist music player for OS X"
|
5
|
-
s.date = '2009-12-
|
5
|
+
s.date = '2009-12-14'
|
6
6
|
s.email = 'deepak.jois@gmail.com'
|
7
7
|
s.homepage = 'http://github.com/deepakjois/dhun'
|
8
8
|
s.has_rdoc = false
|
data/lib/dhun.rb
CHANGED
data/lib/dhun/controller.rb
CHANGED
@@ -23,7 +23,8 @@ module Dhun
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def query(*args)
|
26
|
-
|
26
|
+
abort_if_empty_args(args)
|
27
|
+
q = Query.new(args)
|
27
28
|
if q.is_valid?
|
28
29
|
files = q.execute_spotlight_query
|
29
30
|
puts(files.empty? ? "No Results Found" : "#{files.size} Results\n" + files.join("\n"))
|
@@ -33,6 +34,7 @@ module Dhun
|
|
33
34
|
end
|
34
35
|
|
35
36
|
def play(*args)
|
37
|
+
abort_if_empty_args(args)
|
36
38
|
resp = get_json_response("play", args)
|
37
39
|
return unless resp
|
38
40
|
# Process response
|
@@ -47,6 +49,7 @@ module Dhun
|
|
47
49
|
end
|
48
50
|
|
49
51
|
def enqueue(*args)
|
52
|
+
abort_if_empty_args(args)
|
50
53
|
resp = get_json_response("enqueue",args)
|
51
54
|
return unless resp
|
52
55
|
# Process response
|
@@ -76,6 +79,13 @@ module Dhun
|
|
76
79
|
end
|
77
80
|
end
|
78
81
|
|
82
|
+
def history
|
83
|
+
resp = get_json_response("history")
|
84
|
+
return unless resp
|
85
|
+
puts resp[:message]
|
86
|
+
print_list(resp[:history]) unless resp[:history].empty?
|
87
|
+
end
|
88
|
+
|
79
89
|
def next(*args)
|
80
90
|
resp = get_json_response("next")
|
81
91
|
puts resp[:message] if resp
|
@@ -112,7 +122,7 @@ module Dhun
|
|
112
122
|
resp = client.send(cmd)
|
113
123
|
end
|
114
124
|
|
115
|
-
def get_json_response(command
|
125
|
+
def get_json_response(command,args=[])
|
116
126
|
begin
|
117
127
|
resp = send_command(command,args)
|
118
128
|
return Result.from_json_str(resp)
|
@@ -123,6 +133,10 @@ module Dhun
|
|
123
133
|
end
|
124
134
|
end
|
125
135
|
|
136
|
+
def abort_if_empty_args(args)
|
137
|
+
abort "You must pass in atleast one argument" if args.empty?
|
138
|
+
end
|
139
|
+
|
126
140
|
def print_list(list)
|
127
141
|
list.each { |item| puts item }
|
128
142
|
end
|
data/lib/dhun/handler.rb
CHANGED
@@ -5,13 +5,13 @@ module Dhun
|
|
5
5
|
def stop
|
6
6
|
result = Result.new :success, "Dhun is stopping"
|
7
7
|
Server.stop
|
8
|
-
Player.instance.
|
8
|
+
Player.instance.stop
|
9
9
|
return result.to_json
|
10
10
|
end
|
11
11
|
|
12
12
|
def play(*args)
|
13
13
|
@player = Player.instance
|
14
|
-
q = Query.new(args
|
14
|
+
q = Query.new(args)
|
15
15
|
if q.is_valid?
|
16
16
|
files = q.execute_spotlight_query
|
17
17
|
if files.empty?
|
@@ -57,6 +57,13 @@ module Dhun
|
|
57
57
|
result = Result.new :success, status_msg, :now_playing => now_playing, :queue => queue
|
58
58
|
result.to_json
|
59
59
|
end
|
60
|
+
|
61
|
+
def history
|
62
|
+
@player = Player.instance
|
63
|
+
status_msg = @player.history.empty? ? "No files in history" : "#{@player.history.size} files in history"
|
64
|
+
result = Result.new :success, status_msg, :history => @player.history
|
65
|
+
result.to_json
|
66
|
+
end
|
60
67
|
|
61
68
|
def next(*args)
|
62
69
|
@player = Player.instance
|
data/lib/dhun/player.rb
CHANGED
@@ -5,6 +5,7 @@ module Dhun
|
|
5
5
|
include Singleton
|
6
6
|
|
7
7
|
attr_reader :queue
|
8
|
+
attr_reader :history
|
8
9
|
attr_reader :status
|
9
10
|
attr_reader :current
|
10
11
|
|
@@ -12,6 +13,7 @@ module Dhun
|
|
12
13
|
|
13
14
|
def initialize
|
14
15
|
@queue = []
|
16
|
+
@history = []
|
15
17
|
@logger = Logger.instance
|
16
18
|
@status = :stopped
|
17
19
|
end
|
@@ -46,6 +48,7 @@ module Dhun
|
|
46
48
|
@current = @queue.shift
|
47
49
|
logger.log "Playing #{@current}"
|
48
50
|
DhunExt.play_file @current
|
51
|
+
@history.unshift @current
|
49
52
|
end
|
50
53
|
@status = :stopped
|
51
54
|
logger.log "Finished playing #{@current}"
|
@@ -69,13 +72,14 @@ module Dhun
|
|
69
72
|
|
70
73
|
def stop
|
71
74
|
@status = :stopped
|
72
|
-
@current = nil
|
73
75
|
DhunExt.stop
|
74
76
|
# Wait for @player_thread to exit cleanly
|
75
77
|
@player_thread.join unless @player_thread.nil?
|
78
|
+
logger.debug "Stopped"
|
76
79
|
end
|
77
80
|
|
78
81
|
def next
|
82
|
+
logger.debug "Switching to next"
|
79
83
|
stop # stops current track
|
80
84
|
next_track = @queue.first
|
81
85
|
play # start playing with the next track
|
data/lib/dhun/query.rb
CHANGED
@@ -1,23 +1,49 @@
|
|
1
1
|
require 'dhun_ext'
|
2
|
+
|
2
3
|
module Dhun
|
3
4
|
class Query
|
4
5
|
|
5
6
|
MD_ITEMS = [:kMDItemAlbum, :kMDItemAuthors, :kMDItemComposer, :kMDItemDisplayName, :kMDItemFSName, :kMDItemTitle, :kMDItemMusicalGenre]
|
6
|
-
|
7
|
+
MAPPINGS = { "file" => :kMDItemFSName, "album" => :kMDItemAlbum, "artist" => :kMDItemAuthors, "title" => :kMDItemTitle, "genre" => :kMDItemMusicalGenre }
|
8
|
+
|
7
9
|
attr_reader :spotlight_query
|
8
10
|
|
9
|
-
def initialize(
|
10
|
-
@
|
11
|
+
def initialize(args)
|
12
|
+
@query_args = args
|
11
13
|
parse
|
12
14
|
end
|
13
15
|
|
14
16
|
def parse
|
15
|
-
|
16
|
-
|
17
|
-
|
17
|
+
return if @query_args.empty?
|
18
|
+
filters = []
|
19
|
+
strings = []
|
20
|
+
|
21
|
+
@query_args.each do |arg|
|
22
|
+
# Check if it is a filter
|
23
|
+
if filter?(arg)
|
24
|
+
filters.push(arg)
|
25
|
+
else
|
26
|
+
strings.push(arg)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
mappings = MD_ITEMS.clone
|
31
|
+
fq = filters.collect do |f|
|
32
|
+
fltr,query = *(f.split(":"))
|
33
|
+
md_item = MAPPINGS[fltr]
|
34
|
+
mappings.delete md_item
|
35
|
+
"#{md_item} == '#{query.strip}'wc"
|
36
|
+
end.join(" && ")
|
37
|
+
|
18
38
|
|
19
|
-
|
20
|
-
|
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(" && ")
|
44
|
+
|
45
|
+
@spotlight_query = ["kMDItemContentTypeTree == 'public.audio'", fq, sq].select { |s| s.length > 0 }.join(" && ")
|
46
|
+
Logger.instance.debug @spotlight_query
|
21
47
|
@is_valid = true
|
22
48
|
end
|
23
49
|
|
@@ -25,20 +51,16 @@ module Dhun
|
|
25
51
|
@is_valid
|
26
52
|
end
|
27
53
|
|
54
|
+
def filter?(str)
|
55
|
+
return false unless str.index ":"
|
56
|
+
a,b = *(str.split(":"))
|
57
|
+
# Check if filter is valid
|
58
|
+
return MAPPINGS.keys.member?(a)
|
59
|
+
end
|
60
|
+
|
28
61
|
# Use extension to query spotlight
|
29
62
|
def execute_spotlight_query
|
30
63
|
return DhunExt.query_spotlight(@spotlight_query)
|
31
64
|
end
|
32
|
-
|
33
|
-
def get_metadata_item(field)
|
34
|
-
case field
|
35
|
-
when "album" then :kMDItemAlbum
|
36
|
-
when "artist" then :kMDItemAuthors
|
37
|
-
when "composer" then :kMDItemComposer
|
38
|
-
when "title" then :kMDItemTitle
|
39
|
-
when "genre" then :kMDItemMusicalGenre
|
40
|
-
else "Unknown"
|
41
|
-
end
|
42
|
-
end
|
43
65
|
end
|
44
66
|
end
|
data/lib/dhun/runner.rb
CHANGED
@@ -5,7 +5,7 @@ module Dhun
|
|
5
5
|
# Heavily lifted from Thin codebase
|
6
6
|
class Runner
|
7
7
|
COMMANDS = %w(start query)
|
8
|
-
CLIENT_COMMANDS = %w(stop play pause resume next enqueue status shuffle)
|
8
|
+
CLIENT_COMMANDS = %w(stop play pause resume next enqueue status shuffle history)
|
9
9
|
# Parsed options
|
10
10
|
attr_accessor :options
|
11
11
|
|
@@ -94,7 +94,11 @@ EOF
|
|
94
94
|
|
95
95
|
def run_command
|
96
96
|
controller = Controller.new(@options)
|
97
|
-
|
97
|
+
begin
|
98
|
+
controller.send(@command,*@arguments)
|
99
|
+
rescue ArgumentError
|
100
|
+
abort "Illegal arguments passed to #{@command}"
|
101
|
+
end
|
98
102
|
end
|
99
103
|
end
|
100
104
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dhun
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Deepak Jois
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-12-
|
12
|
+
date: 2009-12-14 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|