mikeplayer 1.0.6 → 1.0.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: da3837b6ce739aa20ed88bf085abd0ecad1be6f88be884e581d601a4463cd548
4
- data.tar.gz: 89e4ce6a4aa879a82b97d17567cc187c323cba56aaba1f56bf3e8a3c1a272ba8
3
+ metadata.gz: 4629aa37d245f2c061c144700a0d23aba06a851085baed86b54a8514c7919146
4
+ data.tar.gz: 1554111b1ae2568d736a248f9310d79ec6198c4f1cb0d672814f287a463d7ddb
5
5
  SHA512:
6
- metadata.gz: 5ea01390ed6529bc297751b3b89b6bba8913370c8d39afc57195ab71906961e2d2b0d630d064e5e1f79a0af413f61583b73f2f4797259ff9069aed50686a8d34
7
- data.tar.gz: bb081e5da791f92addebff815a5d4d63e60e39554387a859eb69849d246f4216f0abfa3c1503eb708d6cbadeb0d082c97048707962664beb85ccf98d1fd8df0c
6
+ metadata.gz: cbaec3a72786231a7c327259539a1aef222b1a8e548e9254ac09ac5a3c65c2a6b39d992f9590450ee382e8f521c6e61031a8b798617517a867f4eebbf7411356
7
+ data.tar.gz: 3bd515e08a89b88cf3e52c21f547d2b056a5472b9ef6db95da378ff7c1b612e79cbbd824623e067d18ee7db218627d67a8244c6db60f1f5c34f0bf06752f2303
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'json'
5
+ require 'mikeplayer'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start
data/lib/mikeplayer.rb CHANGED
@@ -4,29 +4,29 @@ require 'open3'
4
4
  require 'io/console'
5
5
  require 'mp3info'
6
6
  require 'mikeplayer/version'
7
- require 'mikeplayer/settings'
7
+ require 'mikeplayer/display'
8
8
  require 'mikeplayer/playlist'
9
+ require 'mikeplayer/play_thread'
10
+ require 'mikeplayer/settings'
9
11
  require 'mikeplayer/song'
10
12
 
11
13
  module MikePlayer
12
14
  class Player
13
- PAUSE_INDICATOR = "||".freeze
14
- INDICATOR_SIZE = 4
15
- SLEEP_SETTING = 0.5
15
+ PLAY_SLEEP = 0.5
16
+ PAUSE_SLEEP = 1.0
16
17
  STOPPED = :stopped
17
18
  PLAYING = :playing
18
19
  PAUSED = :paused
20
+ SONG_CHANGE = :song_change
19
21
 
20
22
  def initialize(options, *args)
21
23
  @settings = Settings.new(options)
22
24
  @playlist = Playlist.new(@settings.playlist)
23
25
  @minutes = @settings.minutes
24
26
  @command = ''
25
- @pid = nil
26
- @timer_start = nil
27
+ @timer_start = Time.now if (@minutes > 0)
27
28
  @state = STOPPED
28
-
29
- check_system
29
+ @player = PlayThread.new(volume: @settings.volume)
30
30
 
31
31
  if (true == @settings.list?)
32
32
  @songs.map { |song| File.basename(song) }.sort.each {|song| puts "#{File.basename(song)}"}
@@ -58,66 +58,36 @@ module MikePlayer
58
58
  end
59
59
 
60
60
  @thread = Thread.new do
61
- @song_i = 0
62
- display_width = 0
61
+ @display = Display.new
62
+ @song_i = 0
63
63
 
64
64
  while (@song_i < @playlist.size)
65
- song = @playlist.get(@song_i)
66
- @song_start = Time.now
67
- @pause_time = nil
68
- info_prefix = "\r#{@playlist.song_info(@song_i)}".freeze
65
+ @display.song_info = @playlist.song_info(@song_i)
69
66
 
70
- stdin, stdother, thread_info = Open3.popen2e('play', '--no-show-progress', '--volume', @settings.volume, song.filename)
67
+ @player.play(song.filename)
71
68
 
72
69
  @state = PLAYING
73
- @pid = thread_info.pid
74
- indicator = ''
75
- info_changed = false
76
70
 
77
- while (true == pid_alive?)
71
+ while @player.playing?
78
72
  pause_if_over_time_limit
79
73
 
80
- if (true == playing?)
81
- indicator = "#{'>' * (playing_time % INDICATOR_SIZE)}".ljust(INDICATOR_SIZE)
82
- info_changed = true
83
- elsif (true == paused?) && (false == indicator.include?(PAUSE_INDICATOR))
84
- indicator = PAUSE_INDICATOR.ljust(INDICATOR_SIZE)
85
- info_changed = true
86
- end
87
-
88
- if (true == info_changed)
89
- mindicator = ""
90
-
91
- if (0 < minutes_remaining)
92
- mindicator = "(#{minutes_remaining}↓) "
93
- end
94
-
95
- print("\r" << ' '.ljust(display_width))
74
+ @display.elapsed = @player.elapsed if playing?
96
75
 
97
- info = "#{info_prefix} #{song.length_str(playing_time)} #{mindicator}#{indicator}"
76
+ @display.display!(song.length_str(@player.elapsed), minutes_remaining)
98
77
 
99
- print(info)
100
-
101
- display_width = info.size
102
-
103
- info_changed = false
104
- $stdout.flush
105
- end
106
-
107
- sleep SLEEP_SETTING
78
+ sleep(sleep_time)
108
79
  end
109
80
 
110
- stdin.close
111
- stdother.close
112
-
113
- @pid = nil
114
-
115
- if (true == playing?) && (playing_time >= (song.length - 1))
81
+ if playing? && @player.stopped?
116
82
  next_song
83
+ elsif paused?
84
+ while paused?
85
+ sleep(sleep_time)
86
+ end
117
87
  end
118
88
  end
119
89
 
120
- @pid = nil
90
+ @player.stop
121
91
  print("\r\n")
122
92
  exit
123
93
  end
@@ -127,30 +97,8 @@ module MikePlayer
127
97
  print("\r\n")
128
98
  end
129
99
 
130
- def cmd_exist?(cmd)
131
- if (true != system('command'))
132
- raise "Missing 'command' command, which is used to test compatibility."
133
- end
134
-
135
- if (true != system("command -v #{cmd} >/dev/null 2>&1"))
136
- return false
137
- end
138
-
139
- return true
140
- end
141
-
142
100
  private
143
101
 
144
- def check_system
145
- %w(play).each do |cmd|
146
- if (false == cmd_exist?(cmd))
147
- raise "#{cmd} failed, do you have sox installed?"
148
- end
149
- end
150
-
151
- return nil
152
- end
153
-
154
102
  def wait_on_user
155
103
  while ('q' != @command)
156
104
  @command = STDIN.getch
@@ -161,9 +109,8 @@ module MikePlayer
161
109
  next_song
162
110
  elsif ('z' == @command)
163
111
  previous_song
164
- elsif ('q' == @command) && (false == @pid.nil?)
165
- stop_song
166
- @thread.kill
112
+ elsif ('q' == @command)
113
+ press_stop
167
114
  elsif ('t' == @command)
168
115
  @timer_start = Time.now
169
116
  elsif (false == @timer_start.nil?) && ("#{@command.to_i}" == @command)
@@ -185,68 +132,58 @@ module MikePlayer
185
132
  return (PAUSED == @state)
186
133
  end
187
134
 
188
- def press_pause
189
- if (true == playing?)
190
- kill("STOP")
191
- @pause_time = Time.now
192
- @state = PAUSED
193
- elsif (true == paused?)
194
- kill("CONT")
195
- @song_start += (Time.now - @pause_time)
196
- @pause_time = nil
197
- @state = PLAYING
198
- else
199
- print("Confused state #{@state}.")
200
- end
135
+ def changing?
136
+ return (SONG_CHANGE == @state)
201
137
  end
202
138
 
203
- def stop_song
204
- kill("INT")
205
-
206
- sleep 0.2
207
-
208
- if (true == pid_alive?)
209
- kill("KILL")
210
- end
211
-
139
+ def press_stop
140
+ @player.stop
212
141
  @state = STOPPED
213
142
  end
214
143
 
215
- def pid_alive?(pid = @pid)
216
- if (false == pid.nil?)
217
- return system("ps -p #{pid} > /dev/null")
218
- end
144
+ def press_pause
145
+ debug('|')
219
146
 
220
- return false
147
+ if playing?
148
+ debug('>')
149
+ @state = PAUSED
150
+ @display.paused
151
+ @player.pause
152
+ elsif paused?
153
+ debug('|')
154
+ @state = PLAYING
155
+ else
156
+ print("Confused state #{@state}.")
157
+ end
221
158
  end
222
159
 
223
160
  def next_song
224
161
  debug('n')
225
- stop_song
162
+
163
+ @state = SONG_CHANGE
164
+
165
+ @player.stop
226
166
 
227
167
  @song_i += 1
228
168
  end
229
169
 
230
170
  def previous_song
231
171
  debug('p')
232
- stop_song
233
172
 
234
- if (playing_time < 10)
235
- @song_i -= 1 unless @song_i <= 0
173
+ @state = SONG_CHANGE
174
+
175
+ if (@player.elapsed < 10)
176
+ @song_i -= 1 if @song_i.positive?
236
177
  else
237
178
  debug('x')
238
179
  end
239
- end
240
180
 
241
- def kill(signal)
242
- if (false == @pid.nil?)
243
- Process.kill(signal, @pid)
244
- end
181
+ @player.stop
245
182
  end
246
183
 
247
184
  def pause_if_over_time_limit
248
185
  if (false == @timer_start.nil?) && (0 < @minutes) && (true == playing?)
249
- if (0 > minutes_remaining)
186
+ if (minutes_remaining && 0 >= minutes_remaining)
250
187
  press_pause
251
188
  @timer_start = nil
252
189
  @minutes = 0
@@ -254,24 +191,20 @@ module MikePlayer
254
191
  end
255
192
  end
256
193
 
257
- def playing_time
258
- return (Time.now - @song_start).to_i - pause_time
194
+ def minutes_remaining
195
+ return if ((0 == @minutes) || (@timer_start.nil?))
196
+
197
+ (@minutes - ((Time.now - @timer_start).to_i / 60).to_i)
259
198
  end
260
199
 
261
- def pause_time
262
- if (@pause_time.nil?)
263
- return 0
264
- else
265
- return (Time.now - @pause_time).to_i
266
- end
200
+ def sleep_time
201
+ return PLAY_SLEEP if playing?
202
+
203
+ PAUSE_SLEEP
267
204
  end
268
205
 
269
- def minutes_remaining
270
- if ((0 == @minutes) || (@timer_start.nil?))
271
- return -1
272
- else
273
- return (@minutes - ((Time.now - @timer_start).to_i / 60).to_i)
274
- end
206
+ def song
207
+ @playlist.get(@song_i)
275
208
  end
276
209
 
277
210
  def debug(str)
@@ -0,0 +1,49 @@
1
+ module MikePlayer
2
+ class Display
3
+ PAUSE_INDICATOR = '||'.freeze
4
+ INDICATOR_SIZE = 4
5
+
6
+ def initialize
7
+ @width = 0
8
+ @indicator = ''
9
+ @changed = false
10
+ end
11
+
12
+ def song_info=(v)
13
+ @info_prefix = "\r#{v}".freeze
14
+ end
15
+
16
+ def elapsed=(v)
17
+ @indicator = "#{'>' * (v % INDICATOR_SIZE)}".ljust(INDICATOR_SIZE)
18
+ @changed = true
19
+ end
20
+
21
+ def paused
22
+ if (false == @indicator.include?(PAUSE_INDICATOR))
23
+ @indicator = PAUSE_INDICATOR.ljust(INDICATOR_SIZE)
24
+ @changed = true
25
+ end
26
+ end
27
+
28
+ def display!(elapsed_info, countdown = nil)
29
+ return unless changed?
30
+
31
+ mindicator = "(#{countdown}↓) " if countdown
32
+
33
+ print("\r" << ' '.ljust(@width))
34
+
35
+ info = "#{@info_prefix} #{elapsed_info} #{mindicator}#{@indicator}"
36
+
37
+ print(info)
38
+
39
+ @width = info.size
40
+ @changed = false
41
+
42
+ $stdout.flush
43
+ end
44
+
45
+ def changed?
46
+ true == @changed
47
+ end
48
+ end
49
+ end
@@ -1,13 +1,121 @@
1
1
  module MikePlayer
2
2
  class PlayThread
3
- def self.run(file, volume)
3
+ def initialize(volume: 1.0)
4
+ check_system
5
+
6
+ @pid = nil
7
+ @volume = volume
8
+ @start_t = 0
9
+ @elapsed = 0
10
+ @paused = false
11
+ end
12
+
13
+ def play(file)
14
+ start_position = 0
15
+
16
+ if paused?
17
+ start_position = @elapsed
18
+ else
19
+ @elapsed = 0
20
+ end
21
+
22
+ start_thread(file: file, start_position: start_position)
23
+
24
+ @start_t = Time.now.to_i
25
+ end
26
+
27
+ def stop
28
+ pause
29
+
30
+ @elapsed = 0
31
+ @start_t = 0
32
+ @paused = false
33
+ end
34
+
35
+ def pause
36
+ kill('INT')
37
+
38
+ @elapsed += Time.now.to_i - @start_t
39
+ @start_t = 0
40
+
41
+ sleep 0.2
42
+
43
+ kill('KILL')
44
+
45
+ @paused = true
46
+ end
47
+
48
+ def kill(signal)
49
+ Process.kill(signal, @pid) if alive?
50
+ end
51
+
52
+ def alive?
53
+ MikePlayer::PlayThread.alive?(@pid)
54
+ end
55
+
56
+ def stopped?
57
+ false == alive?
58
+ end
59
+
60
+ def paused?
61
+ @paused && stopped?
62
+ end
63
+
64
+ def playing?
65
+ alive?
66
+ end
67
+
68
+ def elapsed
69
+ return (@elapsed + (Time.now.to_i - @start_t)) if @start_t.positive?
70
+
71
+ @elapsed
72
+ end
73
+
74
+ def self.alive?(pid)
75
+ return system("ps -p #{pid} > /dev/null") unless pid.nil?
76
+
77
+ false
78
+ end
79
+
80
+ def self.cmd_exist?(cmd)
81
+ if (true != system('command'))
82
+ raise "Missing 'command' command, which is used to test compatibility."
83
+ end
84
+
85
+ if (true != system("command -v #{cmd} >/dev/null 2>&1"))
86
+ return false
87
+ end
88
+
89
+ return true
90
+ end
91
+
92
+ private
93
+ def start_thread(file:, start_position: )
4
94
  args = [
5
- :play,
95
+ 'play',
6
96
  '--no-show-progress',
7
- '--volume', volume,
8
- song
97
+ '--volume', @volume.to_s,
98
+ file,
99
+ 'trim', start_position.to_s,
9
100
  ]
10
- Open3.popen2e(*args) do |stdin, out, wait_thr|
101
+
102
+ stdin, stdother, thread_info = Open3.popen2e(*args)
103
+
104
+ @pid = thread_info.pid
105
+
106
+ sleep 0.2
107
+
108
+ raise "Failed to play #{stdother.read}" unless alive?
109
+
110
+ stdin.close
111
+ stdother.close
112
+
113
+ self
114
+ end
115
+
116
+ def check_system
117
+ %w[play].each do |cmd|
118
+ raise "#{cmd} failed, do you have sox installed?" unless MikePlayer::PlayThread.cmd_exist?(cmd)
11
119
  end
12
120
  end
13
121
  end
@@ -1,3 +1,3 @@
1
1
  module MikePlayer
2
- VERSION = '1.0.6'.freeze
2
+ VERSION = '1.0.7'.freeze
3
3
  end
data/mikeplayer.gemspec CHANGED
@@ -28,7 +28,7 @@ Gem::Specification.new do |gem|
28
28
  gem.require_paths = ['lib']
29
29
  gem.licenses = ['MIT']
30
30
 
31
- gem.add_dependency 'json', '~> 1.8'
31
+ gem.add_dependency 'json', '~> 2.5'
32
32
  gem.add_dependency 'ruby-mp3info', '~> 0.8'
33
33
  gem.add_dependency 'minitest', '~> 5'
34
34
  gem.add_development_dependency 'rake', '~> 12'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mikeplayer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.6
4
+ version: 1.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Crockett
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-06-07 00:00:00.000000000 Z
11
+ date: 2021-02-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.8'
19
+ version: '2.5'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.8'
26
+ version: '2.5'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: ruby-mp3info
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -92,6 +92,7 @@ email:
92
92
  - rubygems@mmcrockett.com
93
93
  executables:
94
94
  - MikePlayer.rb
95
+ - console
95
96
  extensions: []
96
97
  extra_rdoc_files: []
97
98
  files:
@@ -101,7 +102,9 @@ files:
101
102
  - README.md
102
103
  - Rakefile
103
104
  - bin/MikePlayer.rb
105
+ - bin/console
104
106
  - lib/mikeplayer.rb
107
+ - lib/mikeplayer/display.rb
105
108
  - lib/mikeplayer/executable.rb
106
109
  - lib/mikeplayer/play_thread.rb
107
110
  - lib/mikeplayer/playlist.rb
@@ -116,7 +119,7 @@ homepage: https://github.com/mmcrockett/mikeplayer
116
119
  licenses:
117
120
  - MIT
118
121
  metadata: {}
119
- post_install_message:
122
+ post_install_message:
120
123
  rdoc_options: []
121
124
  require_paths:
122
125
  - lib
@@ -131,9 +134,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
131
134
  - !ruby/object:Gem::Version
132
135
  version: '0'
133
136
  requirements: []
134
- rubyforge_project:
135
- rubygems_version: 2.7.6
136
- signing_key:
137
+ rubygems_version: 3.1.2
138
+ signing_key:
137
139
  specification_version: 4
138
140
  summary: Wraps Sox's `play` command, allowing playslists, find, random and time limit.
139
141
  test_files: