rumu 0.4.0 → 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.
- checksums.yaml +4 -4
- data/bin/rumu +106 -104
- metadata +12 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c513bd3c485e3d4e1e4cd93bd78fd8697f681e06f4b02f621074381b2e3adc74
|
|
4
|
+
data.tar.gz: 31d65a7899a76517cf5259268835f41b5cf21ff49ab7f22173014e0c303c90de
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9f54f7c90953189088f948baa1e7cd1a3e93bdecd93ff0a2fcc367e39a3ce1b15a52992688615ea239739b7ca9f201cea20b2b3269c18d07c80c50cb78dd1704
|
|
7
|
+
data.tar.gz: ceab4d9aabb925ae942c17153a20da8568a87ce3dd98a089525f813718338894ca3dbfe4775143d541e03d96119e1c36e3868381bee1f13654762246f692fa25
|
data/bin/rumu
CHANGED
|
@@ -3,131 +3,133 @@ require 'open3'
|
|
|
3
3
|
require 'shellwords'
|
|
4
4
|
require 'io/console'
|
|
5
5
|
require 'pathname'
|
|
6
|
-
require '
|
|
7
|
-
require 'pulseaudio_simple_ffi'
|
|
6
|
+
require 'pulseaudio_simple_fiddle'
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
ConfigDir="#{Dir.home}/.config/#{pkg}"
|
|
8
|
+
Pkg,Ver='rumu','0.4.2'
|
|
9
|
+
ConfigDir="#{Dir.home}/.config/#{Pkg}"
|
|
12
10
|
Dir.mkdir(ConfigDir) unless File.directory?(ConfigDir)
|
|
13
11
|
|
|
14
12
|
Channels,Rate,WordSize=2,44100,4
|
|
15
13
|
FfmpegFmt="-ac #{Channels} -ar #{Rate} -f f#{WordSize*8}le"
|
|
16
14
|
|
|
17
|
-
class
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
@in,@out,@err,@thr = Open3.popen3("ffmpeg -loglevel -8 #{FfmpegFmt} -i - #{device}")
|
|
21
|
-
@out.close
|
|
22
|
-
@err.close
|
|
23
|
-
end
|
|
24
|
-
def write buf
|
|
25
|
-
@in.write buf
|
|
26
|
-
end
|
|
27
|
-
def close
|
|
28
|
-
@in.close
|
|
29
|
-
end
|
|
15
|
+
class BasicO
|
|
16
|
+
def write(buf) = buf == nil ? buf : @dev.write(buf)
|
|
17
|
+
def close = @dev.close
|
|
30
18
|
end
|
|
31
19
|
|
|
32
|
-
class
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
@device=cfg[1].to_s.chomp.length>0 ? cfg[1] : nil
|
|
40
|
-
end
|
|
41
|
-
File.write(file,@mode.to_s+"\n"+@device.to_s)
|
|
42
|
-
@out= :ffmpeg == @mode ?
|
|
43
|
-
FfmpegPipeO.new(@device) :
|
|
44
|
-
PulseAudioSimpleFFI::PulseAudioSimpleO.new(@device,'Music Playlist',channels:Channels,rate:Rate)
|
|
45
|
-
end
|
|
46
|
-
def write buf
|
|
47
|
-
@out.write buf
|
|
48
|
-
end
|
|
49
|
-
def close
|
|
50
|
-
@out.close
|
|
51
|
-
end
|
|
20
|
+
class FfmpegPipeO < BasicO
|
|
21
|
+
def initialize(device, channels: Channels, rate: Rate, wordsize: WordSize )
|
|
22
|
+
device = device.to_s.chomp.length>0 ? device.to_s.chomp : '-f pulse default'
|
|
23
|
+
@dev,@out,@err,@thr = Open3.popen3("ffmpeg -loglevel -8 #{FfmpegFmt} -i - #{device}")
|
|
24
|
+
@out.close
|
|
25
|
+
@err.close
|
|
26
|
+
end
|
|
52
27
|
end
|
|
53
28
|
|
|
29
|
+
class ConfigO < BasicO
|
|
30
|
+
def initialize file: ConfigDir+'/out'
|
|
31
|
+
@mode,@devname=:pulse,nil
|
|
32
|
+
if File.file?(file)
|
|
33
|
+
cfg=File.read(file).split("\n")
|
|
34
|
+
@mode=cfg[0].to_sym
|
|
35
|
+
@devname=cfg[1].to_s.chomp.length>0 ? cfg[1] : nil
|
|
36
|
+
end
|
|
37
|
+
File.write(file,@mode.to_s+"\n"+@devname.to_s)
|
|
38
|
+
@dev= :ffmpeg == @mode ?
|
|
39
|
+
FfmpegPipeO.new(@devname) :
|
|
40
|
+
PulseAudio::SimpleO.new(Pkg,'Music Playlist',channels:Channels,rate:Rate,device:@devname)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def print_brand = print "\r ] #{Pkg} ✝ v#{Ver} [ "
|
|
45
|
+
|
|
54
46
|
list,list_i,cycle,mode,ssoff,help=[],0,0,:load,'',''
|
|
55
47
|
if ARGV.length==0
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
48
|
+
if File.file?("#{ConfigDir}/list")
|
|
49
|
+
list=File.read("#{ConfigDir}/list").split("\n")
|
|
50
|
+
if File.file?("#{ConfigDir}/pos")
|
|
51
|
+
pos=File.read("#{ConfigDir}/pos").split("\n")
|
|
52
|
+
list_i=pos[0].to_i
|
|
53
|
+
cycle=pos[1].to_i
|
|
54
|
+
cycle-=3 if cycle>3
|
|
55
|
+
ssoff="-ss #{cycle} " if cycle>0
|
|
56
|
+
end
|
|
57
|
+
else
|
|
58
|
+
puts "Usage: #{Pkg} files_to_play"
|
|
59
|
+
exit 1
|
|
60
|
+
end
|
|
69
61
|
else
|
|
70
|
-
|
|
62
|
+
list=ARGV.map{|x| Pathname(x).realpath.to_s}
|
|
71
63
|
end
|
|
72
64
|
prefix=/\A(.*).*(\n\1.*)*\Z/.match(list.join("\n"))[1]
|
|
73
65
|
puts prefix
|
|
74
66
|
|
|
75
|
-
ii,io,ie,it=nil,nil,nil,nil
|
|
76
67
|
oo=ConfigO.new
|
|
68
|
+
bq=SizedQueue.new 4
|
|
69
|
+
|
|
70
|
+
iit=Thread.new {
|
|
71
|
+
io,ie=nil,nil
|
|
72
|
+
until :quit == mode
|
|
73
|
+
if io and io.eof?
|
|
74
|
+
list_i+=1
|
|
75
|
+
mode=list_i>=list.count ? :quit : :load
|
|
76
|
+
end
|
|
77
|
+
if :load == mode
|
|
78
|
+
[io,ie].each{|x|x.close} unless !io or io.closed?
|
|
79
|
+
ii,io,ie,it = Open3.popen3 "ffmpeg -loglevel -8 -i #{Shellwords.escape(list[list_i])} #{ssoff} #{FfmpegFmt} -"
|
|
80
|
+
ii.close
|
|
81
|
+
cycle=0 unless ssoff.length > 0
|
|
82
|
+
puts "#{' '*help.length}\r#{list[list_i][prefix.length..-1]}" unless list[list_i].length == prefix.length
|
|
83
|
+
ssoff,help,mode='','',:play
|
|
84
|
+
end
|
|
85
|
+
bq.push io.read(Channels*Rate*WordSize)
|
|
86
|
+
end
|
|
87
|
+
io.close
|
|
88
|
+
}
|
|
77
89
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
ii.close
|
|
89
|
-
cycle=0 unless ssoff.length > 0
|
|
90
|
-
puts "#{' '*help.length}\r#{list[list_i][prefix.length..-1]}"
|
|
91
|
-
ssoff=''
|
|
92
|
-
help=''
|
|
93
|
-
mode=:play
|
|
94
|
-
when :play
|
|
95
|
-
oo.write(io.read(Channels*Rate*WordSize))
|
|
96
|
-
cycle+=1
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
oo.close
|
|
90
|
+
oot=Thread.new{
|
|
91
|
+
until ( :quit == mode )
|
|
92
|
+
if ! bq.empty?
|
|
93
|
+
oo.write bq.pop
|
|
94
|
+
cycle+=1
|
|
95
|
+
else
|
|
96
|
+
sleep rand
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
oo.close
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
until :quit == mode
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
103
|
+
print "\r#{cycle/60}:#{"%02d"%(cycle%60)} > "
|
|
104
|
+
case ch=IO.console.raw{|c|c.read_nonblock(1) rescue ''}.downcase
|
|
105
|
+
when 'n'
|
|
106
|
+
list_i+=1
|
|
107
|
+
mode= list_i<list.count ? :load : :quit
|
|
108
|
+
when 'r'
|
|
109
|
+
mode=:load
|
|
110
|
+
when 'p'
|
|
111
|
+
if list_i>0
|
|
112
|
+
list_i-=1
|
|
113
|
+
mode=:load
|
|
114
|
+
end
|
|
115
|
+
when 's'
|
|
116
|
+
print 'Seek to: '
|
|
117
|
+
ti=(ts=IO.console.readline.chomp).split(':')
|
|
118
|
+
ssoff="-ss #{ts}"
|
|
119
|
+
cycle=(ti[-1].to_f + ti[-2].to_f*60 + ti[-3].to_f*60*60).to_i
|
|
120
|
+
mode=:load
|
|
121
|
+
when 'q'
|
|
122
|
+
mode=:quit
|
|
123
|
+
File.write(ConfigDir+'/list',list.join("\n"))
|
|
124
|
+
File.write(ConfigDir+'/pos',list_i.to_s+"\n"+cycle.to_s)
|
|
125
|
+
print_brand
|
|
126
|
+
when ''
|
|
127
|
+
sleep rand
|
|
128
|
+
else
|
|
129
|
+
print (help="#{ch} < #{list_i>0?"[P]rev ":""}[R]estart [S]eek [N]ext [Q]uit")
|
|
130
|
+
end
|
|
130
131
|
end
|
|
132
|
+
oot.join
|
|
133
|
+
print_brand
|
|
134
|
+
puts
|
|
131
135
|
|
|
132
|
-
puts "\r ] #{pkg} ✝ v#{ver} [ "
|
|
133
|
-
pt.join
|
metadata
CHANGED
|
@@ -1,29 +1,35 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rumu
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Benjamin Cook
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2024-06-04 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
14
|
+
name: pulseaudio_simple_fiddle
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0.0'
|
|
17
20
|
- - ">="
|
|
18
21
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: 0.0.
|
|
22
|
+
version: 0.0.0
|
|
20
23
|
type: :runtime
|
|
21
24
|
prerelease: false
|
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
26
|
requirements:
|
|
27
|
+
- - "~>"
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '0.0'
|
|
24
30
|
- - ">="
|
|
25
31
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: 0.0.
|
|
32
|
+
version: 0.0.0
|
|
27
33
|
description: rumu is an aggressively minimized audio player that plays a playlist
|
|
28
34
|
gaplessly leveraging command-line ffmpeg and pipes. After a quit, it will return
|
|
29
35
|
to where it left off when run next.
|
|
@@ -53,7 +59,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
53
59
|
version: '0'
|
|
54
60
|
requirements:
|
|
55
61
|
- ffmpeg
|
|
56
|
-
rubygems_version: 3.
|
|
62
|
+
rubygems_version: 3.3.15
|
|
57
63
|
signing_key:
|
|
58
64
|
specification_version: 4
|
|
59
65
|
summary: "(ru)by (mu)usic - a minimal ffmpeg-based gapless audio playlist player"
|