mikeplayer 1.0.6 → 1.0.7
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 +4 -4
- data/bin/console +15 -0
- data/lib/mikeplayer.rb +61 -128
- data/lib/mikeplayer/display.rb +49 -0
- data/lib/mikeplayer/play_thread.rb +113 -5
- data/lib/mikeplayer/version.rb +1 -1
- data/mikeplayer.gemspec +1 -1
- metadata +11 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4629aa37d245f2c061c144700a0d23aba06a851085baed86b54a8514c7919146
|
4
|
+
data.tar.gz: 1554111b1ae2568d736a248f9310d79ec6198c4f1cb0d672814f287a463d7ddb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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/
|
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
|
-
|
14
|
-
|
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
|
-
@
|
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
|
-
@
|
62
|
-
|
61
|
+
@display = Display.new
|
62
|
+
@song_i = 0
|
63
63
|
|
64
64
|
while (@song_i < @playlist.size)
|
65
|
-
|
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
|
-
|
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
|
71
|
+
while @player.playing?
|
78
72
|
pause_if_over_time_limit
|
79
73
|
|
80
|
-
|
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
|
-
|
76
|
+
@display.display!(song.length_str(@player.elapsed), minutes_remaining)
|
98
77
|
|
99
|
-
|
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
|
-
|
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
|
-
@
|
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)
|
165
|
-
|
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
|
189
|
-
|
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
|
204
|
-
|
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
|
216
|
-
|
217
|
-
return system("ps -p #{pid} > /dev/null")
|
218
|
-
end
|
144
|
+
def press_pause
|
145
|
+
debug('|')
|
219
146
|
|
220
|
-
|
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
|
-
|
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
|
-
|
235
|
-
|
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
|
-
|
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
|
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
|
258
|
-
return (
|
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
|
262
|
-
if
|
263
|
-
|
264
|
-
|
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
|
270
|
-
|
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
|
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
|
-
|
95
|
+
'play',
|
6
96
|
'--no-show-progress',
|
7
|
-
'--volume', volume,
|
8
|
-
|
97
|
+
'--volume', @volume.to_s,
|
98
|
+
file,
|
99
|
+
'trim', start_position.to_s,
|
9
100
|
]
|
10
|
-
|
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
|
data/lib/mikeplayer/version.rb
CHANGED
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', '~>
|
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.
|
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:
|
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: '
|
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: '
|
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
|
-
|
135
|
-
|
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:
|