jimmy_jukebox 0.4.1 → 0.4.2
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/bin/play_jukebox +5 -3
- data/lib/jimmy_jukebox/artists.rb +1 -1
- data/lib/jimmy_jukebox/jukebox.rb +31 -20
- data/lib/jimmy_jukebox/song.rb +10 -58
- data/lib/jimmy_jukebox/user_interface.rb +1 -1
- data/lib/jimmy_jukebox/version.rb +1 -1
- metadata +1 -1
data/bin/play_jukebox
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
3
|
+
$running_jruby = defined?(JRUBY_VERSION) || (defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby') || RUBY_PLATFORM == 'java'
|
4
|
+
|
5
|
+
if $running_jruby
|
4
6
|
begin
|
5
7
|
require 'spoon'
|
6
8
|
require 'readline'
|
7
9
|
rescue LoadError => e
|
8
10
|
if e.message =~ /spoon/
|
9
|
-
p "*** You must install
|
11
|
+
p "*** You must run 'gem install spoon' before using JimmyJukebox on JRuby ***"
|
10
12
|
exit
|
11
13
|
elsif e.message =~ /readline/
|
12
14
|
p "*** You must install 'readline' to use JimmyJukebox on JRuby ***"
|
@@ -24,7 +26,7 @@ else
|
|
24
26
|
p "*** You must install 'readline' or the 'rb-readline' gem to use JimmyJukebox in Ruby ***"
|
25
27
|
exit
|
26
28
|
elsif e.message =~ /posix/ || e.message =~ /spawn/
|
27
|
-
p "*** You must install
|
29
|
+
p "*** You must run 'gem install posix-spawn' before using JimmyJukebox in Ruby ***"
|
28
30
|
exit
|
29
31
|
else
|
30
32
|
raise
|
@@ -26,6 +26,7 @@ module Artists
|
|
26
26
|
:lh => "lionel_hampton",
|
27
27
|
:md => "miles_davis",
|
28
28
|
:odjb => "original_dixieland_jazz_band",
|
29
|
+
:rt => "ragtime",
|
29
30
|
:rn => "red_norvo",
|
30
31
|
:sb => "sidney_bechet"
|
31
32
|
}
|
@@ -44,5 +45,4 @@ module Artists
|
|
44
45
|
value.to_s.split("_").map! { |name_component| name_component.capitalize }.join("") + '.yml'
|
45
46
|
end
|
46
47
|
|
47
|
-
|
48
48
|
end
|
@@ -8,8 +8,8 @@ module JimmyJukebox
|
|
8
8
|
class NoCurrentSongException < Exception; end
|
9
9
|
class NoPreviousSongException < Exception; end
|
10
10
|
|
11
|
-
attr_accessor :current_song, :continuous_play
|
12
|
-
attr_writer :user_config, :
|
11
|
+
attr_accessor :current_song, :continuous_play, :songs_played
|
12
|
+
attr_writer :user_config, :next_song, :playing
|
13
13
|
|
14
14
|
def initialize(new_user_config = UserConfig.new, continuous_play = true)
|
15
15
|
self.user_config = new_user_config
|
@@ -19,7 +19,7 @@ module JimmyJukebox
|
|
19
19
|
def play_loop
|
20
20
|
loop do
|
21
21
|
if continuous_play && !playing?
|
22
|
-
p "Playing
|
22
|
+
p "Playing next song"
|
23
23
|
play_next_song
|
24
24
|
else
|
25
25
|
sleep 0.1
|
@@ -28,7 +28,10 @@ module JimmyJukebox
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def next_song
|
31
|
-
|
31
|
+
# reset @next_song each time it's accessed
|
32
|
+
current_next_song = @next_song ? @next_song : random_song
|
33
|
+
@next_song = random_song
|
34
|
+
current_next_song
|
32
35
|
end
|
33
36
|
|
34
37
|
def play_next_song
|
@@ -45,27 +48,37 @@ module JimmyJukebox
|
|
45
48
|
end
|
46
49
|
|
47
50
|
def previous_song
|
48
|
-
|
51
|
+
if songs_played.length >= 2
|
52
|
+
songs_played[songs_played.length-2]
|
53
|
+
else
|
54
|
+
nil
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def songs_played
|
59
|
+
@songs_played ||= []
|
49
60
|
end
|
50
61
|
|
51
62
|
def replay_previous_song
|
52
|
-
if previous_song
|
63
|
+
if previous_song && current_song
|
64
|
+
enable_continuous_play
|
65
|
+
self.next_song = previous_song
|
53
66
|
p "Replaying #{previous_song.music_file}"
|
54
|
-
|
55
|
-
|
67
|
+
current_song.terminate
|
68
|
+
self.current_song = nil
|
69
|
+
self.playing = false
|
56
70
|
else
|
57
71
|
raise NoPreviousSongException, "No previous song"
|
58
72
|
end
|
59
73
|
end
|
60
74
|
|
61
75
|
def skip_song
|
62
|
-
enable_continuous_play
|
63
76
|
if current_song
|
77
|
+
enable_continuous_play
|
64
78
|
p "Skipping #{current_song.music_file}"
|
65
79
|
#play_random_song
|
66
|
-
|
80
|
+
current_song.terminate
|
67
81
|
self.current_song = nil
|
68
|
-
previous_song.terminate
|
69
82
|
self.playing = false
|
70
83
|
else
|
71
84
|
raise NoCurrentSongException, "No current_song"
|
@@ -90,41 +103,39 @@ module JimmyJukebox
|
|
90
103
|
end
|
91
104
|
|
92
105
|
def play_random_song
|
93
|
-
p "Inside play_random_song"
|
94
106
|
play_song(random_song)
|
95
107
|
end
|
96
108
|
|
97
109
|
def enable_continuous_play
|
98
110
|
self.continuous_play = true
|
99
|
-
p "Enabled continuous_play"
|
100
111
|
end
|
101
112
|
|
102
113
|
def disable_continuous_play
|
103
114
|
self.continuous_play = false
|
104
|
-
p "Disabled continuous_play"
|
105
115
|
end
|
106
116
|
|
107
117
|
def play_song(song)
|
108
|
-
terminate_current_song if current_song
|
109
118
|
self.playing = true
|
110
|
-
|
119
|
+
terminate_current_song(play_another: false) if current_song
|
111
120
|
self.current_song = song
|
121
|
+
self.songs_played << song
|
112
122
|
current_song.play(user_config, self)
|
113
123
|
p "Finished playing"
|
114
|
-
|
124
|
+
p "Songs played: " + songs_played.to_s
|
115
125
|
self.current_song = nil
|
116
126
|
self.playing = false
|
117
127
|
rescue Song::SongTerminatedPrematurelyException
|
118
128
|
p "Song ended prematurely"
|
119
129
|
end
|
120
130
|
|
121
|
-
def terminate_current_song
|
131
|
+
def terminate_current_song(opts=nil)
|
132
|
+
# By default, stops song and lets a new song play automatically
|
133
|
+
# To prevent another song from playing automatically, pass "play_another: false"
|
122
134
|
if current_song
|
123
135
|
p "Terminating #{current_song.music_file}"
|
124
136
|
current_song.terminate
|
125
|
-
self.previous_song = current_song
|
126
137
|
self.current_song = nil
|
127
|
-
self.playing = false
|
138
|
+
self.playing = (opts && opts[:play_another]) ? !play_another : false
|
128
139
|
else
|
129
140
|
raise NoCurrentSongException, "No current_song"
|
130
141
|
end
|
data/lib/jimmy_jukebox/song.rb
CHANGED
@@ -37,16 +37,15 @@ module JimmyJukebox
|
|
37
37
|
gpid == 0 ? nil : gpid
|
38
38
|
end
|
39
39
|
|
40
|
+
def process_group_id
|
41
|
+
Process.getpgid(playing_pid)
|
42
|
+
end
|
43
|
+
|
40
44
|
def pause
|
41
45
|
self.paused = true
|
42
|
-
# jruby doesn't seem to handle system() correctly
|
43
|
-
# trying backticks
|
44
|
-
# system("kill -s STOP #{playing_pid}") if playing_pid
|
45
46
|
if grandchild_pid
|
46
|
-
p "Pausing"
|
47
47
|
`kill -s STOP #{grandchild_pid}`
|
48
48
|
elsif playing_pid
|
49
|
-
p "Pausing"
|
50
49
|
`kill -s STOP #{playing_pid}`
|
51
50
|
else
|
52
51
|
raise NoPlayingPidException, "*** Can't pause song because can't find playing_pid #{playing_pid} ***"
|
@@ -55,14 +54,9 @@ module JimmyJukebox
|
|
55
54
|
|
56
55
|
def unpause
|
57
56
|
self.paused = false
|
58
|
-
# jruby doesn't seem to handle system() correctly
|
59
|
-
# trying backticks
|
60
|
-
#system("kill -s CONT #{playing_pid}") if playing_pid
|
61
57
|
if grandchild_pid
|
62
|
-
p "Unpausing"
|
63
58
|
`kill -s CONT #{grandchild_pid}`
|
64
59
|
elsif playing_pid
|
65
|
-
p "Unpausing"
|
66
60
|
`kill -s CONT #{playing_pid}`
|
67
61
|
else
|
68
62
|
raise NoPlayingPidException, "*** Can't unpause song because can't find playing_pid #{playing_pid} ***"
|
@@ -77,17 +71,11 @@ module JimmyJukebox
|
|
77
71
|
p "killed #{grandpid}"
|
78
72
|
end
|
79
73
|
`kill #{playpid}`
|
80
|
-
p "killed #{playpid}"
|
81
74
|
end
|
82
75
|
|
83
76
|
def terminate
|
84
77
|
self.paused = false
|
85
|
-
#`killall #{player}`
|
86
78
|
self.player = nil
|
87
|
-
# killing processes seems problematic in JRuby
|
88
|
-
# I've tried several approaches, and nothing seems reliable
|
89
|
-
#Process.kill("SIGKILL",playing_pid) if playing_pid
|
90
|
-
#Process.kill("SIGTERM",playing_pid) if playing_pid
|
91
79
|
if playing_pid
|
92
80
|
kill_playing_pid_and_children
|
93
81
|
self.playing_pid = nil
|
@@ -118,38 +106,24 @@ module JimmyJukebox
|
|
118
106
|
music_file_path = File.expand_path(music_file)
|
119
107
|
run_command(player, music_file_path)
|
120
108
|
p "playing_pid = " + playing_pid.to_s
|
121
|
-
#
|
122
|
-
# self.playing_pid = pid
|
123
|
-
#end
|
124
|
-
#if running_jruby?
|
125
|
-
Process.waitpid(playing_pid) # Waits for a child process to exit, returns its process id, and sets $? to a Process::Status object
|
126
|
-
#else
|
127
|
-
# Process::waitpid(playing_pid)
|
128
|
-
#end
|
129
|
-
p "Stopped waiting"
|
109
|
+
Process.waitpid(playing_pid) # Waits for a child process to exit, returns its process id, and sets $? to a Process::Status object
|
130
110
|
$? # return Process::Status object with instance methods .stopped?, .exited?, .exitstatus
|
131
111
|
end
|
132
112
|
|
133
113
|
end
|
134
114
|
|
135
|
-
def running_jruby?
|
136
|
-
defined?(JRUBY_VERSION) || RUBY_ENGINE == 'jruby' || RUBY_PLATFORM == 'java'
|
137
|
-
end
|
138
|
-
|
139
115
|
def run_command(command, arg)
|
140
|
-
|
116
|
+
# make system call and get pid so you can pause/terminate process
|
117
|
+
if $running_jruby
|
141
118
|
pid = Spoon.spawnp(command,arg)
|
142
119
|
else
|
143
120
|
begin
|
144
121
|
pid = POSIX::Spawn::spawn(command + ' ' + arg)
|
145
|
-
#pgid = Process.getpgid(pid)
|
146
|
-
#child = POSIX::Spawn::Child.new(command + ' ' + arg)
|
147
|
-
#pid = child.status.pid
|
148
122
|
|
149
|
-
#
|
123
|
+
# posix/spawn is much faster than fork-exec
|
150
124
|
#pid = Process.fork do
|
151
|
-
# exec(command + ' ' + arg)
|
152
|
-
# exit! 127 #
|
125
|
+
# exec(command + ' ' + arg)
|
126
|
+
# exit! 127 # should never be reached
|
153
127
|
#end
|
154
128
|
rescue NotImplementedError
|
155
129
|
raise CannotSpawnProcessException, "*** Cannot play music because we found neither Spoon.spawnp (for JRuby) nor Process.fork (for MRI) ***"
|
@@ -158,26 +132,4 @@ module JimmyJukebox
|
|
158
132
|
self.playing_pid = pid
|
159
133
|
end
|
160
134
|
|
161
|
-
# make system call and get pid so you can terminate process
|
162
|
-
def system_yield_pid(command,arg)
|
163
|
-
# would like to use Process.respond_to?(:fork) but JRuby mistakenly returns true
|
164
|
-
if running_jruby?
|
165
|
-
pid = Spoon.spawnp(command,arg)
|
166
|
-
else
|
167
|
-
begin
|
168
|
-
#spawn(command + ' ' + arg)
|
169
|
-
#pid = POSIX::Spawn::spawn(command + ' ' + arg)
|
170
|
-
|
171
|
-
# create and run block in subprocess (which will terminate with status 0), capture subprocess pid
|
172
|
-
pid = Process.fork do
|
173
|
-
exec(command + ' ' + arg) # replace new process with system call
|
174
|
-
exit! 127 # exit process and return exit status 127; should never be reached
|
175
|
-
end
|
176
|
-
rescue NotImplementedError
|
177
|
-
raise CannotSpawnProcessException, "*** Cannot play music because we found neither Spoon.spawnp (for JRuby) nor Process.fork (for MRI) ***"
|
178
|
-
end
|
179
|
-
end
|
180
|
-
yield pid if block_given? # call block, passing in the subprocess pid
|
181
|
-
end
|
182
|
-
|
183
135
|
end
|
@@ -51,7 +51,7 @@ user_input_thread = Thread.new do
|
|
51
51
|
rescue Interrupt, SystemExit => e
|
52
52
|
p "JimmyJukebox closed by user request. Bye!"
|
53
53
|
jj.quit
|
54
|
-
system('stty', stty_save) unless
|
54
|
+
system('stty', stty_save) unless $running_jruby # Restore original terminal state
|
55
55
|
exit
|
56
56
|
end
|
57
57
|
end
|