mikeplayer 1.1.1 → 1.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 44526118ece6d69a3b2711ec7595ebf65da59a0729e49439b663b8c28d0db6ac
4
- data.tar.gz: fd2a73b35a0d17a834f098a92a8f34485bb67e4d68a7889d05389626f0ea9560
3
+ metadata.gz: b38d5b7fef4b5141b1f884d386ca6d8cbc17b4890aacaac2a649b06aefd84674
4
+ data.tar.gz: 1f38509a5e275b35d9adbb83c4cf09b23c739f999afe71c7d8ffc16ffbd865d6
5
5
  SHA512:
6
- metadata.gz: 1642c31f25824a61692fb4c7a8a0d8b1d61c06369ae7ccb85f231a82fbe3c6f62d7c30e7dbbaf77751fb72f0abc67cfa6b2cabacc795f0eb08bf592db0af8b53
7
- data.tar.gz: 37491c892b710fd8984da1bf95995043a1c7569d04c34856d4b136b00242644f3dc6692088cd75e003749296a838b160f6886ef1907e257abd0d32a490e343ea
6
+ metadata.gz: 0216f0b2f19389ce060bd48fb1ce7bbfbd13a8e9ff3ae461c16830b745c5eaa463e9f4f1c6706e2085338cc44848d11b855e32e0454a98e5f8cdd96ec916939c
7
+ data.tar.gz: a72f9a0446bcc94e87229812029b7de95bfb1d881450d665fce45e8161c0aa9ee83c762bf42d392e08491e68f10c03244819efa8e94499725d767c7be6f02338
data/bin/MikePlayer.rb CHANGED
@@ -14,14 +14,15 @@ OptionParser.new do |opt|
14
14
 
15
15
  EOF
16
16
  opt.on('-s', '--shuffle', 'Shuffle playlist.') { |o| options[:shuffle] = true }
17
- opt.on('-r', '--random n', 'Create playlist with randomly picked n songs.') { |o| options[:random] = o.to_i }
17
+ opt.on('-r', '--random n', Integer, 'Create playlist with randomly picked n songs.') { |o| options[:random] = o }
18
18
  opt.on('-o', '--overwrite', 'Overwrite playlist.') { |o| options[:overwrite] = true }
19
- opt.on('-v', '--volume n', 'Changes default volume.') { |o| options[:volume] = o }
19
+ opt.on('-v', '--volume n', Float, 'Changes default volume.') { |o| options[:volume] = o }
20
20
  opt.on('-p', '--playlist name', 'Play playlist name.') { |o| options[:playlist] = o }
21
21
  opt.on('-l', '--list', 'List songs in playlist.') { |o| options[:list] = true; }
22
22
  opt.on('-d', '--directory name', 'Directory to find mp3s.') { |o| options[:directory] = o }
23
- opt.on('-t', '--time minutes', 'Limit time to number of minutes.') { |o| options[:minutes] = o }
23
+ opt.on('-t', '--time minutes', Integer, 'Limit time to number of minutes.') { |o| options[:minutes] = o }
24
24
  opt.on('-x', '--debug', 'Turn on debug.') { |o| options[:debug] = true }
25
+ opt.on('-f', '--fullscreen', 'Use an alternate full-screen buffer while playing.') { |o| options[:fullscreen] = true }
25
26
  end.parse!
26
27
 
27
28
  MikePlayer::Player.new(options, ARGV).play
@@ -3,24 +3,57 @@ module MikePlayer
3
3
  PAUSE_INDICATOR = '||'.freeze
4
4
  INDICATOR_SIZE = 4
5
5
 
6
+ RESET = "\e[0m".freeze
7
+ TITLE_COLOR = "\e[1;36m".freeze # bold cyan
8
+ DIM_COLOR = "\e[2m".freeze # dim gray
9
+ BANNER_COLOR = "\e[1;37m".freeze # bold white
10
+ ELAPSED_COLOR = "\e[37m".freeze # white
11
+ COUNTDOWN_COLOR = "\e[33m".freeze # yellow
12
+ PLAY_COLOR = "\e[32m".freeze # green
13
+ PAUSE_COLOR = "\e[1;31m".freeze # bold red
14
+
15
+ ENTER_ALT_SCREEN = "\e[?1049h\e[2J\e[H".freeze
16
+ EXIT_ALT_SCREEN = "\e[?1049l".freeze
17
+
18
+ def self.colorize(text, color)
19
+ return text unless $stdout.tty?
20
+
21
+ "#{color}#{text}#{RESET}"
22
+ end
23
+
24
+ def self.enter_fullscreen
25
+ print(ENTER_ALT_SCREEN)
26
+ $stdout.flush
27
+ end
28
+
29
+ def self.exit_fullscreen
30
+ print(EXIT_ALT_SCREEN)
31
+ $stdout.flush
32
+ end
33
+
6
34
  def initialize
7
35
  @width = 0
8
36
  @indicator = ''
37
+ @paused = false
9
38
  @changed = false
39
+ @color = $stdout.tty?
10
40
  end
11
41
 
12
42
  def song_info=(v)
13
- @info_prefix = "\r#{v}".freeze
43
+ @position = v[:position].freeze
44
+ @title = v[:title].freeze
14
45
  end
15
46
 
16
47
  def elapsed=(v)
17
48
  @indicator = "#{'>' * (v % INDICATOR_SIZE)}".ljust(INDICATOR_SIZE)
49
+ @paused = false
18
50
  @changed = true
19
51
  end
20
52
 
21
53
  def paused
22
- if (false == @indicator.include?(PAUSE_INDICATOR))
54
+ if (false == @paused)
23
55
  @indicator = PAUSE_INDICATOR.ljust(INDICATOR_SIZE)
56
+ @paused = true
24
57
  @changed = true
25
58
  end
26
59
  end
@@ -30,13 +63,20 @@ module MikePlayer
30
63
 
31
64
  mindicator = "(#{countdown}↓) " if countdown
32
65
 
33
- print("\r" << ' '.ljust(@width))
66
+ position = colorize(@position, DIM_COLOR)
67
+ title = colorize(@title, TITLE_COLOR)
68
+ elapsed = colorize(elapsed_info, ELAPSED_COLOR)
69
+ indicator = colorize(@indicator, @paused ? PAUSE_COLOR : PLAY_COLOR)
70
+ count = countdown ? colorize(mindicator, COUNTDOWN_COLOR) : ''
34
71
 
35
- info = "#{@info_prefix} #{elapsed_info} #{mindicator}#{@indicator}"
72
+ plain_info = "Playing #{@position}: #{@title} #{elapsed_info} #{mindicator}#{@indicator}"
73
+ info = "\rPlaying #{position}: #{title} #{elapsed} #{count}#{indicator}"
74
+
75
+ print("\r" << ' '.ljust(@width))
36
76
 
37
77
  print(info)
38
78
 
39
- @width = info.size
79
+ @width = plain_info.size
40
80
  @changed = false
41
81
 
42
82
  $stdout.flush
@@ -45,5 +85,13 @@ module MikePlayer
45
85
  def changed?
46
86
  true == @changed
47
87
  end
88
+
89
+ private
90
+
91
+ def colorize(text, color)
92
+ return text unless @color
93
+
94
+ "#{color}#{text}#{RESET}"
95
+ end
48
96
  end
49
97
  end
@@ -3,11 +3,12 @@ module MikePlayer
3
3
  def initialize(volume: 1.0)
4
4
  check_system
5
5
 
6
- @pid = nil
7
- @volume = volume
8
- @start_t = 0
9
- @elapsed = 0
10
- @paused = false
6
+ @pid = nil
7
+ @wait_thread = nil
8
+ @volume = volume
9
+ @start_t = 0
10
+ @elapsed = 0
11
+ @paused = false
11
12
  end
12
13
 
13
14
  def play(file)
@@ -38,25 +39,19 @@ module MikePlayer
38
39
  @elapsed += Time.now.to_i - @start_t
39
40
  @start_t = 0
40
41
 
41
- 10.times do
42
- break unless alive?
43
-
44
- sleep 0.1
45
- end
42
+ @wait_thread&.join(1)
46
43
 
47
44
  kill('KILL')
48
45
 
49
- 10.times do
50
- break unless alive?
51
-
52
- sleep 0.1
53
- end
46
+ @wait_thread&.join
54
47
 
55
48
  @paused = true
56
49
  end
57
50
 
58
51
  def kill(signal)
59
52
  Process.kill(signal, @pid) if alive?
53
+ rescue Errno::ESRCH
54
+ nil
60
55
  end
61
56
 
62
57
  def alive?
@@ -117,7 +112,8 @@ module MikePlayer
117
112
 
118
113
  stdin, stdother, thread_info = Open3.popen2e(*args)
119
114
 
120
- @pid = thread_info.pid
115
+ @pid = thread_info.pid
116
+ @wait_thread = thread_info
121
117
 
122
118
  10.times do
123
119
  break if alive?
@@ -70,7 +70,7 @@ module MikePlayer
70
70
  def song_info(i)
71
71
  song_i_str = "#{i + 1}".rjust(self.size.to_s.size)
72
72
 
73
- return "Playing (#{song_i_str}/#{self.size}): #{get(i).info}".freeze
73
+ return { position: "(#{song_i_str}/#{self.size})", title: get(i).info }
74
74
  end
75
75
 
76
76
  def size
@@ -16,8 +16,9 @@ module MikePlayer
16
16
  @music_dir = options[:directory] || File.join(@home, DEFAULT_DIRECTORY)
17
17
  @settings_dir = options[:settings] || File.join(@home, SETTINGS_DIRECTORY)
18
18
  @minutes = options[:minutes].to_i
19
- @debug = options[:debug]
20
- @random = options[:random].to_i
19
+ @debug = options[:debug]
20
+ @random = options[:random].to_i
21
+ @fullscreen = options[:fullscreen]
21
22
 
22
23
  if (false == Dir.exist?(@settings_dir))
23
24
  Dir.mkdir(@settings_dir)
@@ -48,6 +49,10 @@ module MikePlayer
48
49
  return true == @list
49
50
  end
50
51
 
52
+ def fullscreen?
53
+ return true == @fullscreen
54
+ end
55
+
51
56
  private
52
57
 
53
58
  def find_playlist(user_option)
@@ -4,12 +4,17 @@ module MikePlayer
4
4
 
5
5
  def initialize(filename)
6
6
  @filename = filename
7
- @mp3info = Mp3Info.new(filename)
7
+
8
+ Mp3Info.open(filename) do |mp3info|
9
+ @artist = mp3info.tag.artist.to_s
10
+ @title = mp3info.tag.title.to_s
11
+ @length = mp3info.length || 0
12
+ end
8
13
  end
9
14
 
10
15
  def info
11
- artist = "#{@mp3info.tag.artist}"
12
- title = "#{@mp3info.tag.title}"
16
+ artist = @artist
17
+ title = @title
13
18
 
14
19
  if (true == artist.empty?) && (true == title.empty?)
15
20
  return File.basename(@filename, '.mp3')
@@ -23,7 +28,7 @@ module MikePlayer
23
28
  end
24
29
 
25
30
  def length
26
- return @mp3info.length || 0
31
+ return @length
27
32
  end
28
33
 
29
34
  def length_str(elapsed_time)
@@ -1,3 +1,3 @@
1
1
  module MikePlayer
2
- VERSION = '1.1.1'.freeze
2
+ VERSION = '1.2.0'.freeze
3
3
  end
data/lib/mikeplayer.rb CHANGED
@@ -27,6 +27,7 @@ module MikePlayer
27
27
  @timer_start = Time.now if (@minutes > 0)
28
28
  @state = STOPPED
29
29
  @player = PlayThread.new(volume: @settings.volume)
30
+ @song_mutex = Mutex.new
30
31
 
31
32
  if (true == @settings.list?)
32
33
  @songs.map { |song| File.basename(song) }.sort.each {|song| puts "#{File.basename(song)}"}
@@ -48,8 +49,13 @@ module MikePlayer
48
49
  def play
49
50
  @playlist.shuffle! if @settings.shuffle?
50
51
 
51
- puts "Mike Player v#{MikePlayer::VERSION}"
52
- puts "Playlist #{@playlist.info}\n"
52
+ if @settings.fullscreen?
53
+ Display.enter_fullscreen
54
+ at_exit { Display.exit_fullscreen }
55
+ end
56
+
57
+ puts Display.colorize("Mike Player v#{MikePlayer::VERSION}", Display::BANNER_COLOR)
58
+ puts "#{Display.colorize("Playlist #{@playlist.info}", Display::DIM_COLOR)}\n"
53
59
 
54
60
  if (0 == @playlist.size)
55
61
  puts "No songs in playlist."
@@ -81,6 +87,8 @@ module MikePlayer
81
87
  if playing? && @player.stopped?
82
88
  next_song
83
89
  elsif paused?
90
+ @display.display!(song.length_str(@player.elapsed), minutes_remaining)
91
+
84
92
  while paused?
85
93
  sleep(sleep_time)
86
94
  end
@@ -158,27 +166,35 @@ module MikePlayer
158
166
  end
159
167
 
160
168
  def next_song
161
- debug('n')
169
+ @song_mutex.synchronize do
170
+ return if changing?
162
171
 
163
- @state = SONG_CHANGE
172
+ debug('n')
164
173
 
165
- @player.stop
174
+ @state = SONG_CHANGE
175
+
176
+ @player.stop
166
177
 
167
- @song_i += 1
178
+ @song_i += 1
179
+ end
168
180
  end
169
181
 
170
182
  def previous_song
171
- debug('p')
183
+ @song_mutex.synchronize do
184
+ return if changing?
172
185
 
173
- @state = SONG_CHANGE
186
+ debug('p')
174
187
 
175
- if (@player.elapsed < 10)
176
- @song_i -= 1 if @song_i.positive?
177
- else
178
- debug('x')
179
- end
188
+ @state = SONG_CHANGE
180
189
 
181
- @player.stop
190
+ if (@player.elapsed < 10)
191
+ @song_i -= 1 if @song_i.positive?
192
+ else
193
+ debug('x')
194
+ end
195
+
196
+ @player.stop
197
+ end
182
198
  end
183
199
 
184
200
  def pause_if_over_time_limit
data/mikeplayer.gemspec CHANGED
@@ -34,6 +34,5 @@ Gem::Specification.new do |spec|
34
34
  spec.add_dependency 'json', '~> 2.5'
35
35
  spec.add_dependency 'ruby-mp3info', '~> 0.8'
36
36
  spec.add_dependency 'minitest', '~> 5'
37
- spec.add_development_dependency 'rake', '~> 12'
38
- spec.add_development_dependency 'byebug', '~> 11'
37
+ spec.add_development_dependency 'rake', '~> 13'
39
38
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mikeplayer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Crockett
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2021-03-03 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: json
@@ -58,28 +57,14 @@ dependencies:
58
57
  requirements:
59
58
  - - "~>"
60
59
  - !ruby/object:Gem::Version
61
- version: '12'
60
+ version: '13'
62
61
  type: :development
63
62
  prerelease: false
64
63
  version_requirements: !ruby/object:Gem::Requirement
65
64
  requirements:
66
65
  - - "~>"
67
66
  - !ruby/object:Gem::Version
68
- version: '12'
69
- - !ruby/object:Gem::Dependency
70
- name: byebug
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '11'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '11'
67
+ version: '13'
83
68
  description: |
84
69
  Wraps Sox's `play` command, allowing playslists, find, random and time limit.
85
70
  Once a song is playing you can:
@@ -113,7 +98,6 @@ homepage: https://github.com/mmcrockett/mikeplayer
113
98
  licenses:
114
99
  - MIT
115
100
  metadata: {}
116
- post_install_message:
117
101
  rdoc_options: []
118
102
  require_paths:
119
103
  - lib
@@ -128,8 +112,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
128
112
  - !ruby/object:Gem::Version
129
113
  version: '0'
130
114
  requirements: []
131
- rubygems_version: 3.1.4
132
- signing_key:
115
+ rubygems_version: 3.6.9
133
116
  specification_version: 4
134
117
  summary: Wraps Sox's `play` command, allowing playslists, find, random and time limit.
135
118
  test_files: []