jimmy_jukebox 0.6.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
data/bin/play_jukebox CHANGED
@@ -1,33 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- $running_jruby = defined?(JRUBY_VERSION) || (defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby') || RUBY_PLATFORM == 'java'
4
-
5
- if $running_jruby
6
- begin
7
- require 'spoon'
8
- rescue LoadError => e
9
- if e.message =~ /spoon/
10
- puts "*** You must run 'gem install spoon' before using JimmyJukebox on JRuby ***"
11
- exit
12
- else
13
- raise
14
- end
15
- end
16
- else
17
- begin
18
- require 'posix/spawn'
19
- rescue LoadError => e
20
- if e.message =~ /posix/ || e.message =~ /spawn/
21
- puts "*** You must run 'gem install posix-spawn' before using JimmyJukebox in Ruby ***"
22
- exit
23
- else
24
- raise
25
- end
26
- end
27
- end
28
-
29
3
  lib = File.expand_path('../lib', File.dirname(__FILE__))
30
4
  $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
5
+ require 'jimmy_jukebox/check_gems'
31
6
  require 'jimmy_jukebox'
32
7
  include JimmyJukebox
33
8
 
@@ -85,4 +85,9 @@ module Artists
85
85
  name.to_s.split("_").map! { |name_component| name_component.capitalize }.join("") + '.yml'
86
86
  end
87
87
 
88
+ def prettified_artist_name(name)
89
+ return name.to_s.capitalize unless name.to_s.match(/_/)
90
+ name.to_s.split("_").map! { |name_component| name_component.capitalize }.join(" ")
91
+ end
92
+
88
93
  end
@@ -0,0 +1,25 @@
1
+ $running_jruby = defined?(JRUBY_VERSION) || (defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby') || RUBY_PLATFORM == 'java'
2
+
3
+ if $running_jruby
4
+ begin
5
+ require 'spoon'
6
+ rescue LoadError => e
7
+ if e.message =~ /spoon/
8
+ puts "*** You must run 'gem install spoon' before using JimmyJukebox on JRuby ***"
9
+ exit
10
+ else
11
+ raise
12
+ end
13
+ end
14
+ else
15
+ begin
16
+ require 'posix/spawn'
17
+ rescue LoadError => e
18
+ if e.message =~ /posix/ || e.message =~ /spawn/
19
+ puts "*** You must run 'gem install posix-spawn' before using JimmyJukebox in Ruby ***"
20
+ exit
21
+ else
22
+ raise
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,6 @@
1
+ begin
2
+ require 'io/console'
3
+ rescue LoadError
4
+ puts "*** JimmyJukebox uses io/console, which is built into Ruby 1.9.3. I recommend running JimmyJukebox on 1.9.3. You could instead install the 'io-console' gem, but the most recent version works only with 1.9.3, so try \"gem install io-console -v '0.3'\" ***"
5
+ exit
6
+ end
@@ -0,0 +1,9 @@
1
+ if JimmyJukebox::RUNNING_JRUBY
2
+ class IO
3
+ def getch
4
+ raw do
5
+ getc
6
+ end
7
+ end
8
+ end
9
+ end
@@ -8,7 +8,7 @@ module JimmyJukebox
8
8
 
9
9
  def display_options_after_delay
10
10
  # pause to let song display song info and begin playing before displaying user options
11
- sleep 1
11
+ sleep 0.4
12
12
  display_options
13
13
  end
14
14
 
@@ -1,19 +1,49 @@
1
+ require 'jimmy_jukebox/artists'
2
+
1
3
  module JimmyJukebox
2
4
 
3
5
  module HandleLoadJukeboxInput
4
6
 
5
7
  def no_argv0
6
- puts "You must select an artist to use 'load_jukebox'."
7
- puts "For example: 'load_jukebox at' to load Art Tatum"
8
- puts "Another example: 'load_jukebox dr' to load Django Reinhardt"
8
+ display_template {
9
+ puts " You must select an artist or genre to use 'load_jukebox'.\n\n"
10
+ puts " Examples:\n\n"
11
+ puts " load_jukebox at (to download Art Tatum)\n\n"
12
+ puts " load_jukebox dr (to download Django Reinhardt)\n\n"
13
+ puts " load_jukebox bluegrass (to download bluegrass)\n\n"
14
+ puts " load_jukebox classical (to download classical)\n\n"
15
+ puts " load_jukebox jazz (to download jazz)\n\n"
16
+ }
9
17
  exit
10
18
  end
11
19
 
20
+ def list_artists
21
+ display_template {
22
+ puts " Artist symbol = Artist name (Genre)\n\n"
23
+ ARTISTS.each do |k,v|
24
+ puts " " + k.to_s.rjust(5) + ' = ' + prettified_artist_name(v[:name]) + ' (' + v[:genre].capitalize + ')'
25
+ end
26
+ puts "\n"
27
+ }
28
+ end
29
+
12
30
  def invalid_artist
13
- puts "No action taken in response to your command 'load_jukebox #{ARGV[0]}'."
14
- puts "JimmyJukebox does not recognize '#{ARGV[0]}'. You must select a valid artist."
15
- puts "For example, valid artists include: 'bh' for Billie Holiday, 'cb' for Count Basie, and 'lh' for Lionel Hampton"
16
- puts "Please see the README for a complete list of valid artists."
31
+ display_template {
32
+ puts " No action taken in response to your command 'load_jukebox #{ARGV[0]}'.\n\n"
33
+ puts " JimmyJukebox does not recognize '#{ARGV[0]}'.\n\n"
34
+ puts " You must select a valid artist or genre.\n\n"
35
+ puts " Valid genres:\n\n"
36
+ puts " 'bluegrass'"
37
+ puts " 'banjo'"
38
+ puts " 'classical'"
39
+ puts " 'jazz'"
40
+ puts " 'rock'\n\n"
41
+ puts " Valid artists include:\n\n"
42
+ puts " 'bh' for Billie Holiday"
43
+ puts " 'cb' for Count Basie"
44
+ puts " 'lh' for Lionel Hampton.\n\n"
45
+ puts " Please visit the link below for a complete list of valid artists.\n\n"
46
+ }
17
47
  exit
18
48
  end
19
49
 
@@ -35,6 +65,11 @@ module JimmyJukebox
35
65
  arg && arg.to_i.is_a?(Integer) && arg.to_i > 0
36
66
  end
37
67
 
68
+ def play_radio
69
+ require 'jimmy_jukebox/check_gems'
70
+ require 'jimmy_jukebox/user_interface'
71
+ end
72
+
38
73
  def process_artist
39
74
  if valid_integer?(ARGV[1])
40
75
  JimmyJukebox::SongLoader.new.send(artist_name(ARGV[0]), ARGV[1].to_i)
@@ -43,6 +78,31 @@ module JimmyJukebox
43
78
  end
44
79
  end
45
80
 
81
+ def process_genre
82
+ if valid_integer?(ARGV[1])
83
+ JimmyJukebox::SongLoader.new.download_sample_genre(ARGV[1].to_i, ARGV[0].upcase)
84
+ else
85
+ display_genre_download_requires_n_message
86
+ end
87
+ end
88
+
89
+ def display_template(&msg)
90
+ puts " ------------------------------------------------------------------------"
91
+ puts " JimmyJukebox usage help\n\n"
92
+ msg.call if msg
93
+ puts " Full instructions: https://github.com/JamesLavin/jimmy_jukebox"
94
+ puts " ------------------------------------------------------------------------"
95
+ end
96
+
97
+ def display_genre_download_requires_n_message
98
+ display_template {
99
+ puts " You requested a sample of #{ARGV[0]} songs without specifying how many.\n\n"
100
+ puts " Please try again but specify how many songs you wish to download.\n\n"
101
+ puts " For example, to download 10 #{ARGV[0]} songs, type:\n\n"
102
+ puts " load_jukebox #{ARGV[0]} 10"
103
+ }
104
+ end
105
+
46
106
  def process_sample
47
107
  if ARGV[1].nil?
48
108
  JimmyJukebox::SongLoader.new.download_sample_genre(1)
@@ -36,7 +36,7 @@ module JimmyJukebox
36
36
  disable_monitor_powerdown if JimmyJukebox::RUNNING_X_WINDOWS
37
37
  self.user_config = new_user_config
38
38
  self.continuous_play = continuous_play
39
- raise NoSongsException if songs.empty?
39
+ raise NoSongsException if downloaded_song_paths.empty?
40
40
  end
41
41
 
42
42
  def play_loop
@@ -49,10 +49,13 @@ module JimmyJukebox
49
49
  end
50
50
  end
51
51
 
52
+ def next_song?
53
+ @next_song
54
+ end
55
+
52
56
  def next_song
53
57
  # reset @next_song each time it's accessed
54
- current_next_song = @next_song ? @next_song : random_song
55
- @next_song = random_song
58
+ current_next_song, @next_song = [@next_song || random_song, random_song]
56
59
  current_next_song
57
60
  end
58
61
 
@@ -62,7 +65,7 @@ module JimmyJukebox
62
65
 
63
66
  def quit
64
67
  disable_continuous_play
65
- terminate_current_song
68
+ terminate_current_song if current_song
66
69
  end
67
70
 
68
71
  def playing?
@@ -126,15 +129,23 @@ module JimmyJukebox
126
129
  current_song.unpause
127
130
  end
128
131
 
129
- def songs
130
- user_config.songs
132
+ def downloaded_song_paths
133
+ user_config.song_paths
131
134
  end
132
135
 
136
+ #def undownloaded_songs
137
+ # user_config.undownloaded_songs
138
+ #end
139
+
133
140
  def random_song
134
- raise NoNewSongException, "JimmyJukebox can't find any songs to play!" if songs.length == 0
135
- Song.new( songs[rand(songs.length)] )
141
+ raise NoNewSongException, "JimmyJukebox can't find any songs to play!" if downloaded_song_paths.length == 0
142
+ Song.new( downloaded_song_paths[rand(downloaded_song_paths.length)] )
136
143
  end
137
144
 
145
+ #def play_random_undownloaded_song
146
+ # play_song(random_undownloaded_song)
147
+ #end
148
+
138
149
  def play_random_song
139
150
  play_song(random_song)
140
151
  end
@@ -12,6 +12,12 @@ no_argv0 unless ARGV[0]
12
12
 
13
13
  if ARGV[0] =~ /sample/i
14
14
  process_sample
15
+ elsif ARGV[0] =~ /artists/i
16
+ list_artists
17
+ elsif ARGV[0] =~ /radio/i
18
+ play_radio
19
+ elsif valid_genre?(ARGV[0])
20
+ process_genre
15
21
  elsif valid_artist?(ARGV[0])
16
22
  process_artist
17
23
  else
@@ -55,10 +55,12 @@ module JimmyJukebox
55
55
 
56
56
  def pause
57
57
  self.paused = true
58
- if grandchild_pid
59
- `kill -s STOP #{grandchild_pid}`
60
- elsif playing_pid
61
- `kill -s STOP #{playing_pid}`
58
+ if playing_pid
59
+ if grandchild_pid
60
+ `kill -s STOP #{grandchild_pid}`
61
+ else
62
+ `kill -s STOP #{playing_pid}`
63
+ end
62
64
  else
63
65
  raise NoPlayingPidException, "*** Can't pause song because can't find playing_pid #{playing_pid} ***"
64
66
  end
@@ -66,21 +68,21 @@ module JimmyJukebox
66
68
 
67
69
  def unpause
68
70
  self.paused = false
69
- if grandchild_pid
70
- `kill -s CONT #{grandchild_pid}`
71
- elsif playing_pid
71
+ if playing_pid
72
+ if grandchild_pid
73
+ `kill -s CONT #{grandchild_pid}`
74
+ else playing_pid
72
75
  `kill -s CONT #{playing_pid}`
76
+ end
73
77
  else
74
78
  raise NoPlayingPidException, "*** Can't unpause song because can't find playing_pid #{playing_pid} ***"
75
79
  end
76
80
  end
77
81
 
78
82
  def kill_playing_pid_and_children
83
+ return nil unless playpid = playing_pid
79
84
  grandpid = grandchild_pid
80
- playpid = playing_pid
81
- if grandpid
82
- `kill #{grandpid}`
83
- end
85
+ `kill #{grandpid}` if grandpid
84
86
  `kill #{playpid}`
85
87
  end
86
88
 
@@ -41,8 +41,8 @@ module JimmyJukebox
41
41
 
42
42
  attr_reader :user_config
43
43
 
44
- def initialize
45
- @user_config = UserConfig.new
44
+ def initialize(user_config = nil)
45
+ @user_config = user_config || UserConfig.new
46
46
  ARTISTS.values.each { |artist| define_artist artist[:name].to_sym }
47
47
  end
48
48
 
@@ -56,24 +56,24 @@ module JimmyJukebox
56
56
  end
57
57
  end
58
58
 
59
- def all_songs(genre = nil) # valid genres: 'JAZZ', 'CLASSICAL', 'BLUEGRASS', 'BANJO', 'ROCK'
60
- all_songs = {}
59
+ def all_downloadable_songs(genre = nil) # valid genres: 'JAZZ', 'CLASSICAL', 'BLUEGRASS', 'BANJO', 'ROCK'
60
+ result = {}
61
61
  ARTISTS.values.each do |artist|
62
62
  next if genre && artist[:genre] != genre
63
63
  fn = File.dirname(__FILE__) + "/songs/#{artist_name_to_yaml_file(artist[:name].to_s)}"
64
64
  if File.exists?(fn)
65
65
  YAML::load_file(fn).each do |song|
66
- all_songs[song] = artist
66
+ result[song] = artist
67
67
  end
68
68
  end
69
69
  end
70
- all_songs
70
+ result
71
71
  end
72
72
 
73
73
  def sample_genre(num_songs, genre = nil)
74
74
  # loop through array and download num_songs new songs (or until end of array reached)
75
75
  sample = {}
76
- available_songs = all_songs(genre)
76
+ available_songs = all_downloadable_songs(genre)
77
77
  num_songs.times do
78
78
  unless available_songs.length == 0
79
79
  k, v = available_songs.rand_pair!
@@ -2,8 +2,10 @@ require 'fileutils'
2
2
  require 'forwardable'
3
3
  require 'rbconfig'
4
4
 
5
+ require 'jimmy_jukebox/constants'
5
6
  require 'jimmy_jukebox/artists'
6
7
  require 'jimmy_jukebox/song'
8
+ require 'jimmy_jukebox/song_loader'
7
9
  require 'jimmy_jukebox/music_player_detector'
8
10
  include Artists
9
11
 
@@ -29,7 +31,7 @@ module JimmyJukebox
29
31
  extend Forwardable
30
32
 
31
33
  attr_writer :music_directories
32
- attr_accessor :songs, :music_player_detector, :argv0
34
+ attr_accessor :song_paths, :music_player_detector, :argv0
33
35
  def_delegators :@music_player_detector, :ogg_player, :mp3_player, :wav_player, :flac_player
34
36
 
35
37
  DEFAULT_PLAYLIST_DIR = File.expand_path(File.join("~",".jimmy_jukebox"))
@@ -42,7 +44,7 @@ module JimmyJukebox
42
44
  end
43
45
 
44
46
  def initialize
45
- self.songs = []
47
+ self.song_paths = []
46
48
  self.argv0 = ARGV[0]
47
49
  set_music_players
48
50
  generate_directories_list
@@ -195,11 +197,21 @@ module JimmyJukebox
195
197
  end
196
198
  files.delete_if { |f| AUDIO_FORMATS.keys.all? { |re| !f.match(re) } }
197
199
  files.map! { |f| File.expand_path(music_dir) + '/' + f }
198
- files.each { |f| songs << f }
200
+ files.each { |f| song_paths << f }
199
201
  end
200
- puts "WARNING: JimmyJukebox could not find any songs" unless songs.length > 0
201
- #songs = ["~/Music/Artie_Shaw/Georgia On My Mind 1941.mp3",
202
- # "~/Music/Jelly_Roll_Morton/High Society 1939.mp3"]
202
+ puts "WARNING: JimmyJukebox could not find any songs" unless song_paths.length > 0
203
+ #song_paths = ["/home/xxx/Music/Artie_Shaw/Georgia On My Mind 1941.mp3",
204
+ # "/home/xxx/Music/Jelly_Roll_Morton/High Society 1939.mp3"]
205
+ end
206
+
207
+ def undownloaded_songs
208
+ result = {}
209
+ JimmyJukebox::SongLoader.new(self).all_downloadable_songs.each do |url, artist|
210
+ save_path = root_music_dir + artist_name_to_subdir_name(artist[:name]) + '/' + File.basename(url)
211
+ next if song_paths.include?(save_path)
212
+ result[url] = artist
213
+ end
214
+ result
203
215
  end
204
216
 
205
217
  end
@@ -0,0 +1,68 @@
1
+ require 'jimmy_jukebox/check_io_console'
2
+ require 'jimmy_jukebox/jukebox'
3
+ require 'jimmy_jukebox/check_jruby'
4
+
5
+ module JimmyJukebox
6
+
7
+ class UserInputHandler
8
+
9
+ class NoPlayLoopThreadException < Exception; end
10
+
11
+ attr_accessor :jukebox
12
+
13
+ def initialize(jukebox)
14
+ self.jukebox = jukebox
15
+ end
16
+
17
+ def set_get_char_method
18
+ @get_char_method = if JimmyJukebox::RUNNING_JRUBY
19
+ lambda { STDIN.getch }
20
+ else
21
+ lambda {
22
+ begin
23
+ stty_state = `stty -g`
24
+ system("stty raw opost -echo -icanon isig")
25
+ STDIN.getc.chr
26
+ ensure
27
+ `stty #{stty_state}`
28
+ end
29
+ }
30
+ end
31
+ end
32
+
33
+ def get_char
34
+ @get_char_method.call
35
+ end
36
+
37
+ def repl
38
+ set_get_char_method
39
+ loop do
40
+ case char = get_char
41
+ when "q", "Q"
42
+ raise Interrupt
43
+ when "e", "E"
44
+ jukebox.erase_song
45
+ when "p", "P"
46
+ if jukebox.current_song.paused?
47
+ jukebox.unpause_current_song
48
+ else
49
+ puts "Pausing. To unpause, enter 'p' again"
50
+ jukebox.pause_current_song
51
+ end
52
+ when "r", "R"
53
+ jukebox.replay_previous_song
54
+ when "s", "S"
55
+ jukebox.skip_song
56
+ else
57
+ puts "#{char.strip} is not a valid response" if char
58
+ end
59
+ end
60
+ rescue Interrupt, SystemExit => e
61
+ puts "JimmyJukebox closed by user request. Bye!"
62
+ jukebox.quit
63
+ exit
64
+ end
65
+
66
+ end
67
+
68
+ end
@@ -1,19 +1,4 @@
1
- begin
2
- require 'io/console'
3
- rescue LoadError
4
- puts "*** JimmyJukebox uses io/console, which is built into Ruby 1.9.3. I recommend running JimmyJukebox on 1.9.3. You could instead install the 'io-console' gem, but the most recent version works only with 1.9.3, so try \"gem install io-console -v '0.3'\" ***"
5
- exit
6
- end
7
-
8
- if JimmyJukebox::RUNNING_JRUBY
9
- class IO
10
- def getch
11
- raw do
12
- getc
13
- end
14
- end
15
- end
16
- end
1
+ require 'jimmy_jukebox/user_input_handler'
17
2
 
18
3
  jj = Jukebox.new
19
4
 
@@ -22,49 +7,13 @@ play_loop_thread = Thread.new do
22
7
  jj.play_loop
23
8
  end
24
9
 
10
+ uih = UserInputHandler.new(jj)
11
+
25
12
  user_input_thread = Thread.new do
26
13
 
27
- class NoPlayLoopThreadException < Exception; end
14
+ raise NoPlayLoopThreadException, "Can't find play_loop_thread" unless play_loop_thread
15
+ uih.repl
28
16
 
29
- begin
30
- loop do
31
- if JimmyJukebox::RUNNING_JRUBY
32
- char = STDIN.getch
33
- else
34
- begin
35
- stty_state = `stty -g`
36
- system("stty raw opost -echo -icanon isig")
37
- char = STDIN.getc.chr
38
- ensure
39
- `stty #{stty_state}`
40
- end
41
- end
42
- case char
43
- when "q", "Q"
44
- raise Interrupt
45
- when "e", "E"
46
- jj.erase_song
47
- when "p", "P"
48
- raise NoPlayLoopThreadException, "Can't find play_loop_thread" unless play_loop_thread
49
- if jj.current_song.paused?
50
- jj.unpause_current_song
51
- else
52
- puts "Pausing. To unpause, enter 'p' again"
53
- jj.pause_current_song
54
- end
55
- when "r", "R"
56
- jj.replay_previous_song
57
- when "s", "S"
58
- jj.skip_song
59
- else
60
- puts "#{char.strip} is not a valid response" if char
61
- end
62
- end
63
- rescue Interrupt, SystemExit => e
64
- puts "JimmyJukebox closed by user request. Bye!"
65
- jj.quit
66
- exit
67
- end
68
17
  end
69
18
 
70
19
  play_loop_thread.join
@@ -1,4 +1,4 @@
1
1
  module JimmyJukebox
2
- VERSION = '0.6.0'
3
- DATE = '2013-03-26'
2
+ VERSION = '0.6.1'
3
+ DATE = '2013-03-28'
4
4
  end
@@ -48,6 +48,7 @@ describe Jukebox do
48
48
  let(:song2_path) { File.expand_path('~/Music/Rock/Beatles/Sgt_Pepper.mp3') }
49
49
  let(:song3_path) { File.expand_path('~/Music/Rock/Eagles/Hotel_California.ogg') }
50
50
  let(:jb) { Jukebox.new(uc) }
51
+ let(:downloaded) { jb.downloaded_song_paths }
51
52
 
52
53
  before do
53
54
  [song1_path, song2_path, song3_path].each do |song|
@@ -59,10 +60,10 @@ describe Jukebox do
59
60
  end
60
61
 
61
62
  it "generates a non-empty song list" do
62
- jb.songs.should_not be_nil
63
- jb.songs.should_not be_empty
64
- jb.songs.length.should == 3
65
- jb.songs.grep(/Abbey_Road.mp3/).length.should == 1
63
+ downloaded.should_not be_nil
64
+ downloaded.should_not be_empty
65
+ downloaded.length.should == 3
66
+ downloaded.grep(/Abbey_Road.mp3/).length.should == 1
66
67
  end
67
68
 
68
69
  it "can quit" do
@@ -72,9 +73,8 @@ describe Jukebox do
72
73
  play_loop_thread = Thread.new do
73
74
  jb.play_loop
74
75
  end
75
- sleep 0.5
76
+ sleep 0.1
76
77
  jb.playing?.should be_true
77
- p jb.current_song
78
78
  jb.quit
79
79
  end
80
80
 
@@ -84,26 +84,26 @@ describe SongLoader do
84
84
 
85
85
  end
86
86
 
87
- describe "#all_songs" do
87
+ describe "#all_downloadable_songs" do
88
88
 
89
89
  context "no genre specified" do
90
90
 
91
- let(:all_songs) { SongLoader.new.all_songs }
91
+ let(:all_downloadable_songs) { SongLoader.new.all_downloadable_songs }
92
92
 
93
93
  it "should include songs from artist lists" do
94
- all_songs.keys.should include "http://archive.org/download/MozartSinfoniaConcertanteK.364spivakovMintz/02Mozart_SinfoniaConcertanteInEFlatK364-2.Andante.mp3"
95
- all_songs.keys.should include "http://archive.org/download/WinnerRagtimeBand-TheTurkeyTrot1912/WinnerRagtimeBand-TurkeyTrot1912.mp3"
94
+ all_downloadable_songs.keys.should include "http://archive.org/download/MozartSinfoniaConcertanteK.364spivakovMintz/02Mozart_SinfoniaConcertanteInEFlatK364-2.Andante.mp3"
95
+ all_downloadable_songs.keys.should include "http://archive.org/download/WinnerRagtimeBand-TheTurkeyTrot1912/WinnerRagtimeBand-TurkeyTrot1912.mp3"
96
96
  end
97
97
 
98
98
  end
99
99
 
100
100
  context "genre 'JAZZ' specified" do
101
101
 
102
- let(:all_songs) { SongLoader.new.all_songs('JAZZ') }
102
+ let(:all_downloadable_songs) { SongLoader.new.all_downloadable_songs('JAZZ') }
103
103
 
104
104
  it "should include only songs from jazz artist lists" do
105
- all_songs.keys.should_not include "http://archive.org/download/MozartSinfoniaConcertanteK.364spivakovMintz/02Mozart_SinfoniaConcertanteInEFlatK364-2.Andante.mp3"
106
- all_songs.keys.should include "http://archive.org/download/WinnerRagtimeBand-TheTurkeyTrot1912/WinnerRagtimeBand-TurkeyTrot1912.mp3"
105
+ all_downloadable_songs.keys.should_not include "http://archive.org/download/MozartSinfoniaConcertanteK.364spivakovMintz/02Mozart_SinfoniaConcertanteInEFlatK364-2.Andante.mp3"
106
+ all_downloadable_songs.keys.should include "http://archive.org/download/WinnerRagtimeBand-TheTurkeyTrot1912/WinnerRagtimeBand-TurkeyTrot1912.mp3"
107
107
  end
108
108
 
109
109
  end
data/spec/song_spec.rb CHANGED
@@ -11,10 +11,12 @@ module JimmyJukebox
11
11
  def spawn_method
12
12
  if JimmyJukebox::RUNNING_JRUBY
13
13
  require 'spoon'
14
- lambda { |command, arg| Spoon.spawnp('sleep 2') }
14
+ lambda { |command, arg| Spoon.spawnp('sleep 5') }
15
15
  else
16
16
  require 'posix/spawn'
17
- lambda { |command, arg| POSIX::Spawn::spawn('sleep 2') }
17
+ # no idea why ';boguscommand' works, but tests fail without it
18
+ #lambda { |command, arg| POSIX::Spawn::spawn('sleep 2; boguscommand') }
19
+ lambda { |command, arg| POSIX::Spawn::spawn('sleep 5') }
18
20
  end
19
21
  end
20
22
  end
@@ -28,16 +30,28 @@ describe Song do
28
30
  expect {Song.new}.to raise_error
29
31
  end
30
32
 
31
- it "fails if parameter does not end in .mp3 or .ogg" do
32
- expect {Song.new("/home/bill/music_file")}.to raise_error
33
+ it "fails if parameter does not have file extension" do
34
+ expect {Song.new(File.expand_path("~/music_file"))}.to raise_error
33
35
  end
34
36
 
35
37
  it "accepts a parameter ending in .mp3" do
36
- Song.new("/home/bill/music_file.mp3").is_a?(Song)
38
+ Song.new(File.expand_path("~/music_file.mp3")).is_a?(Song)
37
39
  end
38
40
 
39
41
  it "accepts a parameter ending in .ogg" do
40
- Song.new("/home/bill/music_file.ogg").is_a?(Song)
42
+ Song.new(File.expand_path("~/music_file.ogg")).is_a?(Song)
43
+ end
44
+
45
+ it "accepts a parameter ending in .flac" do
46
+ Song.new(File.expand_path("~/music_file.flac")).is_a?(Song)
47
+ end
48
+
49
+ it "accepts a parameter ending in .wav" do
50
+ Song.new(File.expand_path("~/music_file.wav")).is_a?(Song)
51
+ end
52
+
53
+ it "handles uppercase file extensions" do
54
+ Song.new(File.expand_path("~/music_file.WAV")).is_a?(Song)
41
55
  end
42
56
 
43
57
  it "sets a music file" do
@@ -46,6 +60,12 @@ describe Song do
46
60
  song.music_file.should == mf
47
61
  end
48
62
 
63
+ it "sets a music file when passed with ~" do
64
+ mf = "~/Music/JAZZ/billie_holiday.ogg"
65
+ song = Song.new(mf)
66
+ song.music_file.should == File.expand_path(mf)
67
+ end
68
+
49
69
  end
50
70
 
51
71
  describe "#paused?" do
@@ -53,26 +73,41 @@ describe Song do
53
73
  before(:each) do
54
74
  @uc = UserConfig.new
55
75
  @jj = Jukebox.new(@uc, false)
56
- @song = Song.new("~/Music/JAZZ/art_tatum.mp3")
57
76
  end
58
77
 
59
78
  it "is initially not paused" do
60
- @jj.play_song(@song)
61
- @song.paused?.should be_false
79
+ Thread.new do
80
+ song = Song.new("~/Music/JAZZ/art_tatum.mp3")
81
+ @jj.play_song(song)
82
+ end
83
+ sleep 0.1
84
+ @jj.should be_playing
85
+ @jj.current_song.paused?.should be_false
86
+ @jj.quit
62
87
  end
63
88
 
64
89
  it "is paused after calling #pause" do
65
- @jj.play_song(@song)
90
+ Thread.new do
91
+ song = Song.new("~/Music/JAZZ/art_tatum.mp3")
92
+ @jj.play_song(song)
93
+ end
94
+ sleep 0.1
66
95
  @jj.pause_current_song
67
- @song.paused?.should be_true
96
+ @jj.current_song.paused?.should be_true
97
+ @jj.quit
68
98
  end
69
99
 
70
100
  it "is unpaused after calling #pause and #unpause" do
71
- @jj.play_song(@song)
72
- @song.pause
73
- @song.paused?.should be_true
74
- @song.unpause
75
- @song.paused?.should be_false
101
+ Thread.new do
102
+ song = Song.new("~/Music/JAZZ/art_tatum.mp3")
103
+ @jj.play_song(song)
104
+ end
105
+ sleep 0.1
106
+ @jj.current_song.pause
107
+ @jj.current_song.paused?.should be_true
108
+ @jj.current_song.unpause
109
+ @jj.current_song.paused?.should be_false
110
+ @jj.quit
76
111
  end
77
112
 
78
113
  end
@@ -82,37 +117,61 @@ describe Song do
82
117
  before(:each) do
83
118
  @uc = UserConfig.new
84
119
  @jj = Jukebox.new(@uc, false)
85
- @song = Song.new("~/Music/JAZZ/art_tatum.mp3")
86
- end
87
-
88
- it "is initially not paused" do
89
- @jj.play_song(@song)
90
- @song.playing_pid.should be_kind_of(Integer)
91
- @jj.skip_song
92
- @song.playing_pid.should be_nil
120
+ @jj.stub(:downloaded_song_paths).and_return(['~/Music/JAZZ/Duke_Ellington/song1.ogg','~/Music/CLASSICAL/Bach/song2.mp3'])
121
+ #@song = Song.new("~/Music/JAZZ/art_tatum.mp3")
93
122
  end
94
123
 
95
124
  end
96
125
 
97
- describe "#play_loop" do
126
+ describe "#play_loop & #skip_song" do
98
127
 
99
128
  before(:each) do
100
129
  @uc = UserConfig.new
101
- #FileUtils.mkdir_p(File.expand_path("~/Music/JAZZ"))
102
- @song = Song.new("~/Music/JAZZ/art_tatum.mp3")
103
- Jukebox.any_instance.stub(:songs).and_return([@song])
104
- Jukebox.any_instance.stub(:next_song).and_return(@song)
105
- end
106
-
107
- it "should automatically play the first song" do
130
+ @song1 = "~/Music/JAZZ/art_tatum.mp3"
131
+ @song2 = "~/Music/JAZZ/dizzy.mp3"
132
+ @song3 = "~/Music/JAZZ/earl_hines.mp3"
133
+ @song4 = "~/Music/CLASSICAL/beethoven.mp3"
108
134
  @jj = Jukebox.new(@uc)
109
- play_loop_thread = Thread.new do
135
+ @jj.stub(:downloaded_song_paths).and_return([@song1, @song2, @song3, @song4])
136
+ @play_loop_thread = Thread.new do
110
137
  @jj.play_loop
111
138
  end
112
139
  sleep 0.1
113
- @jj.playing?.should be_true
114
- play_loop_thread.exit
115
140
  end
141
+
142
+ describe "#play_loop" do
143
+
144
+ it "should automatically play the first song" do
145
+ @jj.should be_playing
146
+ @jj.downloaded_song_paths.map { |f| File.expand_path(f) }.should include @jj.current_song.music_file
147
+ @play_loop_thread.exit
148
+ end
149
+
150
+ end
151
+
152
+ describe "#skip_song" do
153
+
154
+ it "is initially not paused" do
155
+ test_thread = Thread.new do
156
+ @jj.should be_playing
157
+ puts @jj.current_song.playing_pid
158
+ puts @jj.current_song.music_file
159
+ first_song_pid = @jj.current_song.playing_pid
160
+ sleep 0.5
161
+ @jj.skip_song
162
+ puts @jj.current_song.playing_pid
163
+ puts @jj.current_song.music_file
164
+ @jj.current_song.playing_pid.should_not == first_song_pid
165
+ @jj.should be_playing
166
+ end
167
+ [@play_loop_thread, test_thread].each do |t|
168
+ t.join
169
+ end
170
+ @play_loop_thread.exit
171
+ end
172
+
173
+ end
174
+
116
175
  end
117
176
 
118
177
  end
@@ -128,32 +128,60 @@ describe UserConfig do
128
128
 
129
129
  end
130
130
 
131
- describe "#files" do
131
+ describe "#song_paths and #undownloaded_songs" do
132
132
  let(:user_config) { UserConfig.new }
133
- let(:dir1) { '~/Music/artist1' }
134
- let(:dir2) { '~/Music/artist2' }
133
+ let(:dir1) { '~/Music/JAZZ/John_Coltrane' }
134
+ let(:dir2) { '~/Music/CLASSICAL/Vivaldi' }
135
135
  let(:d1) { File.expand_path(dir1) }
136
136
  let(:d2) { File.expand_path(dir2) }
137
137
 
138
138
  before(:each) do
139
139
  FileUtils.mkdir_p(d1)
140
- FileUtils.mkdir_p(d1 + '/subdir')
141
140
  FileUtils.mkdir_p(d2)
142
- FileUtils.touch d1 + '/song1.mp3'
143
- FileUtils.touch d1 + '/subdir/song2.ogg'
144
- FileUtils.touch d1 + '/subdir/song5.afdsdf'
145
- FileUtils.touch d2 + '/song3.flac'
146
- FileUtils.touch d2 + '/song4.wav'
147
- FileUtils.touch d2 + '/song5.WAV'
141
+ FileUtils.touch d1 + '/a_love_supreme.mp3'
142
+ FileUtils.touch d1 + '/my_funny_valentine.ogg'
143
+ FileUtils.touch d1 + '/song5.afdsdf'
144
+ FileUtils.touch d2 + '/four_seasons.flac'
145
+ FileUtils.touch d2 + '/spring.wav'
146
+ FileUtils.touch d2 + '/Summer.WAV'
148
147
  end
149
148
 
150
- it "generates a complete song list" do
151
- user_config.songs.should include File.expand_path(d1 + '/song1.mp3')
152
- user_config.songs.should include File.expand_path(d1 + '/subdir/song2.ogg')
153
- user_config.songs.should include File.expand_path(d2 + '/song3.flac')
154
- user_config.songs.should include File.expand_path(d2 + '/song4.wav')
155
- user_config.songs.should include File.expand_path(d2 + '/song5.WAV')
156
- user_config.songs.length.should == 5
149
+ describe "#song_paths" do
150
+
151
+ it "generates a complete song list" do
152
+ user_config.song_paths.should include File.expand_path(d1 + '/a_love_supreme.mp3')
153
+ user_config.song_paths.should include File.expand_path(d1 + '/my_funny_valentine.ogg')
154
+ user_config.song_paths.should include File.expand_path(d2 + '/four_seasons.flac')
155
+ user_config.song_paths.should include File.expand_path(d2 + '/spring.wav')
156
+ user_config.song_paths.should include File.expand_path(d2 + '/Summer.WAV')
157
+ user_config.song_paths.length.should == 5
158
+ end
159
+
160
+ it "does not include the invalid-formatted song in the list" do
161
+ user_config.song_paths.should_not include File.expand_path(d1 + '/song5.afdsdf')
162
+ end
163
+
164
+ end
165
+
166
+ describe "#undownloaded_songs" do
167
+
168
+ before do
169
+ @song_hash = {'http://www.mp3.com/a_love_supreme.mp3' => {:genre => 'JAZZ', :name => 'john_coltrane'},
170
+ 'http://www.flac.net/four_seasons.flac' => {:genre => 'CLASSICAL', :name => 'vivaldi'},
171
+ 'http://www.wav.com/winter.wav' => {:genre => 'CLASSICAL', :name => 'vivaldi'},
172
+ 'http://www.ogg.org/maybeline.ogg' => {:genre => 'ROCK', :name => 'chuck_berry'}
173
+ }
174
+ end
175
+
176
+ it "correctly generates the list of undownloaded songs" do
177
+ JimmyJukebox::SongLoader.any_instance.stub(:all_downloadable_songs).and_return(@song_hash)
178
+ undownloaded_urls = user_config.undownloaded_songs.keys
179
+ undownloaded_urls.should include 'http://www.wav.com/winter.wav'
180
+ undownloaded_urls.should include 'http://www.ogg.org/maybeline.ogg'
181
+ undownloaded_urls.should_not include 'http://www.flac.net/four_seasons.flac'
182
+ undownloaded_urls.should_not include 'http://www.mp3.com/a_love_supreme.mp3'
183
+ end
184
+
157
185
  end
158
186
 
159
187
  end
@@ -214,39 +242,39 @@ describe UserConfig do
214
242
 
215
243
  let(:uc) { UserConfig.new }
216
244
 
217
- context "with no songs" do
245
+ context "with no song_paths" do
218
246
 
219
- it "finds no songs" do
220
- uc.songs.length.should == 0
247
+ it "finds no song_paths" do
248
+ uc.song_paths.length.should == 0
221
249
  end
222
250
 
223
251
  end
224
252
 
225
- context "with songs in ~/Music" do
253
+ context "with song_paths in ~/Music" do
226
254
 
227
255
  before(:each) do
228
256
  FileUtils.mkdir_p File.expand_path("~/Music")
229
257
  FileUtils.touch File.expand_path("~/Music/Yellow_Submarine.mp3")
230
258
  end
231
259
 
232
- it "finds songs" do
233
- uc.songs.should_not be_empty
234
- uc.songs.length.should == 1
260
+ it "finds song_paths" do
261
+ uc.song_paths.should_not be_empty
262
+ uc.song_paths.length.should == 1
235
263
  end
236
264
 
237
265
  end
238
266
 
239
- context "with songs in ~/Music subdirectory" do
267
+ context "with song_paths in ~/Music subdirectory" do
240
268
 
241
269
  before do
242
270
  FileUtils.mkdir_p File.expand_path("~/Music/ROCK/Beatles")
243
271
  FileUtils.touch File.expand_path("~/Music/ROCK/Beatles/Yellow_Submarine.mp3")
244
272
  end
245
273
 
246
- it "finds songs" do
274
+ it "finds song_paths" do
247
275
  File.directory?(File.expand_path("~/Music/ROCK/Beatles")).should be_true
248
- uc.songs.should_not be_empty
249
- uc.songs.length.should == 1
276
+ uc.song_paths.should_not be_empty
277
+ uc.song_paths.length.should == 1
250
278
  end
251
279
 
252
280
  end
metadata CHANGED
@@ -1,114 +1,125 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jimmy_jukebox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
5
- prerelease:
4
+ prerelease:
5
+ version: 0.6.1
6
6
  platform: ruby
7
7
  authors:
8
8
  - James Lavin
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-26 00:00:00.000000000 Z
12
+ date: 2013-03-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: !ruby/object:Gem::Requirement
17
- none: false
16
+ version_requirements: !ruby/object:Gem::Requirement
18
17
  requirements:
19
- - - ! '>='
18
+ - - ">="
20
19
  - !ruby/object:Gem::Version
21
- version: '0'
22
- type: :development
23
- prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
20
+ version: !binary |-
21
+ MA==
25
22
  none: false
23
+ requirement: !ruby/object:Gem::Requirement
26
24
  requirements:
27
- - - ! '>='
25
+ - - ">="
28
26
  - !ruby/object:Gem::Version
29
- version: '0'
27
+ version: !binary |-
28
+ MA==
29
+ none: false
30
+ prerelease: false
31
+ type: :development
30
32
  - !ruby/object:Gem::Dependency
31
33
  name: rspec-core
32
- requirement: !ruby/object:Gem::Requirement
33
- none: false
34
+ version_requirements: !ruby/object:Gem::Requirement
34
35
  requirements:
35
- - - ! '>='
36
+ - - ">="
36
37
  - !ruby/object:Gem::Version
37
- version: '0'
38
- type: :development
39
- prerelease: false
40
- version_requirements: !ruby/object:Gem::Requirement
38
+ version: !binary |-
39
+ MA==
41
40
  none: false
41
+ requirement: !ruby/object:Gem::Requirement
42
42
  requirements:
43
- - - ! '>='
43
+ - - ">="
44
44
  - !ruby/object:Gem::Version
45
- version: '0'
45
+ version: !binary |-
46
+ MA==
47
+ none: false
48
+ prerelease: false
49
+ type: :development
46
50
  - !ruby/object:Gem::Dependency
47
51
  name: rspec-mocks
48
- requirement: !ruby/object:Gem::Requirement
49
- none: false
52
+ version_requirements: !ruby/object:Gem::Requirement
50
53
  requirements:
51
- - - ! '>='
54
+ - - ">="
52
55
  - !ruby/object:Gem::Version
53
- version: '0'
54
- type: :development
55
- prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
56
+ version: !binary |-
57
+ MA==
57
58
  none: false
59
+ requirement: !ruby/object:Gem::Requirement
58
60
  requirements:
59
- - - ! '>='
61
+ - - ">="
60
62
  - !ruby/object:Gem::Version
61
- version: '0'
63
+ version: !binary |-
64
+ MA==
65
+ none: false
66
+ prerelease: false
67
+ type: :development
62
68
  - !ruby/object:Gem::Dependency
63
69
  name: rspec-expectations
64
- requirement: !ruby/object:Gem::Requirement
65
- none: false
70
+ version_requirements: !ruby/object:Gem::Requirement
66
71
  requirements:
67
- - - ! '>='
72
+ - - ">="
68
73
  - !ruby/object:Gem::Version
69
- version: '0'
70
- type: :development
71
- prerelease: false
72
- version_requirements: !ruby/object:Gem::Requirement
74
+ version: !binary |-
75
+ MA==
73
76
  none: false
77
+ requirement: !ruby/object:Gem::Requirement
74
78
  requirements:
75
- - - ! '>='
79
+ - - ">="
76
80
  - !ruby/object:Gem::Version
77
- version: '0'
81
+ version: !binary |-
82
+ MA==
83
+ none: false
84
+ prerelease: false
85
+ type: :development
78
86
  - !ruby/object:Gem::Dependency
79
87
  name: fakefs
80
- requirement: !ruby/object:Gem::Requirement
81
- none: false
88
+ version_requirements: !ruby/object:Gem::Requirement
82
89
  requirements:
83
- - - ! '>='
90
+ - - ">="
84
91
  - !ruby/object:Gem::Version
85
- version: '0'
86
- type: :development
87
- prerelease: false
88
- version_requirements: !ruby/object:Gem::Requirement
92
+ version: !binary |-
93
+ MA==
89
94
  none: false
95
+ requirement: !ruby/object:Gem::Requirement
90
96
  requirements:
91
- - - ! '>='
97
+ - - ">="
92
98
  - !ruby/object:Gem::Version
93
- version: '0'
99
+ version: !binary |-
100
+ MA==
101
+ none: false
102
+ prerelease: false
103
+ type: :development
94
104
  - !ruby/object:Gem::Dependency
95
105
  name: fakeweb
96
- requirement: !ruby/object:Gem::Requirement
97
- none: false
106
+ version_requirements: !ruby/object:Gem::Requirement
98
107
  requirements:
99
- - - ! '>='
108
+ - - ">="
100
109
  - !ruby/object:Gem::Version
101
- version: '0'
102
- type: :development
103
- prerelease: false
104
- version_requirements: !ruby/object:Gem::Requirement
110
+ version: !binary |-
111
+ MA==
105
112
  none: false
113
+ requirement: !ruby/object:Gem::Requirement
106
114
  requirements:
107
- - - ! '>='
115
+ - - ">="
108
116
  - !ruby/object:Gem::Version
109
- version: '0'
110
- description: jimmy_jukebox downloads great music and plays random MP3 & OGG songs
111
- under a directory (or set of directories)
117
+ version: !binary |-
118
+ MA==
119
+ none: false
120
+ prerelease: false
121
+ type: :development
122
+ description: jimmy_jukebox downloads great music and plays random MP3 & OGG songs under a directory (or set of directories)
112
123
  email: james@jameslavin.com
113
124
  executables:
114
125
  - play_jukebox
@@ -119,11 +130,15 @@ files:
119
130
  - roadmap.txt
120
131
  - LICENSE.txt
121
132
  - lib/jimmy_jukebox.rb
133
+ - lib/jimmy_jukebox/check_jruby.rb
122
134
  - lib/jimmy_jukebox/handle_load_jukebox_input.rb
135
+ - lib/jimmy_jukebox/check_gems.rb
136
+ - lib/jimmy_jukebox/user_input_handler.rb
123
137
  - lib/jimmy_jukebox/display_options.rb
124
138
  - lib/jimmy_jukebox/music_player_detector.rb
125
139
  - lib/jimmy_jukebox/load_jukebox_code.rb
126
140
  - lib/jimmy_jukebox/user_interface.rb
141
+ - lib/jimmy_jukebox/check_io_console.rb
127
142
  - lib/jimmy_jukebox/user_config.rb
128
143
  - lib/jimmy_jukebox/jukebox.rb
129
144
  - lib/jimmy_jukebox/constants.rb
@@ -192,27 +207,28 @@ files:
192
207
  - bin/load_jukebox
193
208
  homepage: https://github.com/JamesLavin/jimmy_jukebox
194
209
  licenses: []
195
- post_install_message: I really hope you enjoy the great jazz, classical, bluegrass,
196
- and early rock music downloadable using this gem!
210
+ post_install_message: I really hope you enjoy the great jazz, classical, bluegrass, and early rock music downloadable using this gem!
197
211
  rdoc_options: []
198
212
  require_paths:
199
213
  - lib
200
214
  required_ruby_version: !ruby/object:Gem::Requirement
201
- none: false
202
215
  requirements:
203
- - - ! '>='
216
+ - - ">="
204
217
  - !ruby/object:Gem::Version
205
- version: '0'
206
- required_rubygems_version: !ruby/object:Gem::Requirement
218
+ version: !binary |-
219
+ MA==
207
220
  none: false
221
+ required_rubygems_version: !ruby/object:Gem::Requirement
208
222
  requirements:
209
- - - ! '>='
223
+ - - ">="
210
224
  - !ruby/object:Gem::Version
211
- version: '0'
225
+ version: !binary |-
226
+ MA==
227
+ none: false
212
228
  requirements: []
213
229
  rubyforge_project: jimmy_jukebox
214
- rubygems_version: 1.8.23
215
- signing_key:
230
+ rubygems_version: 1.8.24
231
+ signing_key:
216
232
  specification_version: 3
217
233
  summary: plays your MP3 & OGG files and lets you easily download music
218
234
  test_files:
@@ -224,4 +240,3 @@ test_files:
224
240
  - spec/song_loader_spec.rb
225
241
  - spec/load_jukebox_code_spec.rb
226
242
  - spec/jimmy_jukebox_spec.rb
227
- has_rdoc: