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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/bin/rumu +106 -104
  3. metadata +12 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a1965b7e8026eb72e0cfd4c9f4b74523adf96c2d64a30508df01283a51f6ef80
4
- data.tar.gz: 287bb2634da8ce13cf4d1380ac29561b4f747bafdd8c79b69c05acbdc3910907
3
+ metadata.gz: c513bd3c485e3d4e1e4cd93bd78fd8697f681e06f4b02f621074381b2e3adc74
4
+ data.tar.gz: 31d65a7899a76517cf5259268835f41b5cf21ff49ab7f22173014e0c303c90de
5
5
  SHA512:
6
- metadata.gz: 2139d62a2b4eac691d693a2092b9fb4721382fe10295f811b6a98d25a7852005567641974e50c52c06f5f3a79ab95d40c5dd678cb26579bd41a40f02b585e909
7
- data.tar.gz: 94a7861eebfc123955fa8315ac111fc44b2c85945127d62cfef552bfd733ff4c2f28e448f2bb5690002deb28cfda0c3cc4b41032ec8317974b87a23eae7c592e
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 'ffi'
7
- require 'pulseaudio_simple_ffi'
6
+ require 'pulseaudio_simple_fiddle'
8
7
 
9
- pkg='rumu'
10
- ver='0.4.0'
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 FfmpegPipeO
18
- def initialize(device, channels: Channels, rate: Rate, wordsize: WordSize )
19
- device = device.to_s.chomp.length>0 ? device.to_s.chomp : '-f pulse default'
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 ConfigO
33
- def initialize file: ConfigDir+'/out'
34
- @mode=:pulse
35
- @device=nil
36
- if File.file?(file)
37
- cfg=File.read(file).split("\n")
38
- @mode=cfg[0].to_sym
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
- if File.file?("#{ConfigDir}/list")
57
- list=File.read("#{ConfigDir}/list").split("\n")
58
- if File.file?("#{ConfigDir}/pos")
59
- pos=File.read("#{ConfigDir}/pos").split("\n")
60
- list_i=pos[0].to_i
61
- cycle=pos[1].to_i
62
- cycle-=3 if cycle>3
63
- ssoff="-ss #{cycle} " if cycle>0
64
- end
65
- else
66
- puts "Usage: #{pkg} files_to_play"
67
- exit 1
68
- end
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
- list=ARGV.map{|x|Pathname(x).realpath.to_s}
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
- pt=Thread.new{
79
- until :quit == mode
80
- if io and io.eof?
81
- list_i+=1
82
- mode=list_i>=list.count ? :quit : :load
83
- end
84
- case mode
85
- when :load #load new track
86
- [io,ie].each{|x|x.close} unless !io or io.closed?
87
- ii,io,ie,it = Open3.popen3 "ffmpeg -loglevel -8 -i #{Shellwords.escape(list[list_i])} #{ssoff} #{FfmpegFmt} -"
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
- 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
- when ''
126
- sleep rand
127
- else
128
- print (help="#{ch} < #{list_i>0?"[P]rev ":""}[R]estart [S]eek [N]ext [Q]uit")
129
- end
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.0
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: 2021-04-02 00:00:00.000000000 Z
11
+ date: 2024-06-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: pulseaudio_simple_ffi
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.1
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.1
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.2.15
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"