about summary refs log tree commit homepage
path: root/lib/dtas/source
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dtas/source')
-rw-r--r--lib/dtas/source/av.rb7
-rw-r--r--lib/dtas/source/av_ff_common.rb47
-rw-r--r--lib/dtas/source/cmd.rb2
-rw-r--r--lib/dtas/source/common.rb2
-rw-r--r--lib/dtas/source/ff.rb8
-rw-r--r--lib/dtas/source/file.rb2
-rw-r--r--lib/dtas/source/mp3gain.rb2
-rw-r--r--lib/dtas/source/sox.rb13
-rw-r--r--lib/dtas/source/splitfx.rb5
9 files changed, 54 insertions, 34 deletions
diff --git a/lib/dtas/source/av.rb b/lib/dtas/source/av.rb
index 0a9d39b..dcebcfd 100644
--- a/lib/dtas/source/av.rb
+++ b/lib/dtas/source/av.rb
@@ -1,4 +1,4 @@
-# Copyright (C) 2013-2016 all contributors <dtas-all@nongnu.org>
+# Copyright (C) all contributors <dtas-all@nongnu.org>
 # License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
 # frozen_string_literal: true
 require_relative '../../dtas'
@@ -13,13 +13,12 @@ class DTAS::Source::Av # :nodoc:
       'avconv -v error $SSPOS $PROBE -i "$INFILE" $AMAP -f sox - |' \
       'sox -p $SOXFMT - $TRIMFX $RGFX',
 
-    # this is above ffmpeg because this av is the Debian default and
-    # it's easier for me to test av than ff
-    "tryorder" => 1,
+    "tryorder" => 2,
   )
 
   def initialize
     command_init(AV_DEFAULTS)
+    @mcache = nil
     @av_ff_probe = "avprobe"
   end
 
diff --git a/lib/dtas/source/av_ff_common.rb b/lib/dtas/source/av_ff_common.rb
index ae654ba..7f197e0 100644
--- a/lib/dtas/source/av_ff_common.rb
+++ b/lib/dtas/source/av_ff_common.rb
@@ -1,4 +1,4 @@
-# Copyright (C) 2013-2016 all contributors <dtas-all@nongnu.org>
+# Copyright (C) all contributors <dtas-all@nongnu.org>
 # License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
 # frozen_string_literal: true
 require_relative '../../dtas'
@@ -7,10 +7,10 @@ require_relative '../replaygain'
 require_relative '../xs'
 require_relative 'file'
 
-# Common code for libav (avconv/avprobe) and ffmpeg (and ffprobe)
-# TODO: newer versions of both *probes support JSON, which will be easier to
-# parse.  However, the packaged libav version in Debian 7.0 does not
-# support JSON, so we have an ugly parser...
+# Common code for ffmpeg/ffprobe and the abandoned libav (avconv/avprobe).
+# TODO: newer versions of both *probes support JSON, which will be easier
+# to parse.  libav is abandoned, nowadays, and Debian only packages
+# ffmpeg+ffprobe nowadays.
 module DTAS::Source::AvFfCommon # :nodoc:
   include DTAS::Source::File
   include DTAS::XS
@@ -21,10 +21,23 @@ module DTAS::Source::AvFfCommon # :nodoc:
   attr_reader :format
   attr_reader :duration
 
+  CACHE_KEYS = [ :@duration, :@probe_harder, :@comments, :@astreams,
+                 :@format ].freeze
+
+  def mcache_lookup(infile)
+    (@mcache ||= DTAS::Mcache.new).lookup(infile) do |input, dst|
+      tmp = source_file_dup(infile, nil, nil)
+      tmp.av_ff_ok? or return nil
+      CACHE_KEYS.each { |k| dst[k] = tmp.instance_variable_get(k) }
+      dst
+    end
+  end
+
   def try(infile, offset = nil, trim = nil)
-    rv = source_file_dup(infile, offset, trim)
-    rv.av_ff_ok? or return
-    rv
+    ent = mcache_lookup(infile) or return
+    ret = source_file_dup(infile, offset, trim)
+    CACHE_KEYS.each { |k| ret.instance_variable_set(k, ent[k]) }
+    ret
   end
 
   def __parse_astream(cmd, stream)
@@ -79,7 +92,7 @@ module DTAS::Source::AvFfCommon # :nodoc:
 
       err = "".b
       begin
-        s = qx(@env, cmd, err_str: err, no_raise: true)
+        s = qx(@env, cmd, err_str: err, no_raise: true, rlimit_cpu: [ 1, 2 ])
       rescue Errno::ENOENT # avprobe/ffprobe not installed
         return false
       end
@@ -104,13 +117,14 @@ module DTAS::Source::AvFfCommon # :nodoc:
       prev_cmd = cmd
     end while incomplete.compact[0]
 
+    enc = Encoding.default_external # typically Encoding::UTF_8
     # old avprobe
     s.scan(%r{^\[FORMAT\]\n(.*?)\n\[/FORMAT\]\n}m) do |_|
       f = $1.dup
       f =~ /^duration=([\d\.]+)\s*$/nm and @duration = $1.to_f
       # TODO: multi-line/multi-value/repeated tags
       f.gsub!(/^TAG:([^=]+)=(.*)$/ni) { |_|
-        @comments[DTAS.dedupe_str($1.upcase)] = DTAS.dedupe_str($2)
+        @comments[-DTAS.try_enc($1.upcase, enc)] = $2
       }
     end
 
@@ -118,13 +132,22 @@ module DTAS::Source::AvFfCommon # :nodoc:
     s.scan(%r{^\[format\.tags\]\n(.*?)\n\n}m) do |_|
       f = $1.dup
       f.gsub!(/^([^=]+)=(.*)$/ni) { |_|
-        @comments[DTAS.dedupe_str($1.upcase)] = DTAS.dedupe_str($2)
+        @comments[-DTAS.try_enc($1.upcase, enc)] = $2
       }
     end
     s.scan(%r{^\[format\]\n(.*?)\n\n}m) do |_|
       f = $1.dup
       f =~ /^duration=([\d\.]+)\s*$/nm and @duration = $1.to_f
     end
+    comments.each do |k,v|
+      v.chomp!
+      comments[k] = -DTAS.try_enc(v, enc)
+    end
+
+    # ffprobe always uses "track", favor FLAC convention "TRACKNUMBER":
+    if @comments['TRACK'] && !@comments['TRACKNUMBER']
+      @comments['TRACKNUMBER'] = @comments.delete('TRACK')
+    end
 
     ! @astreams.compact.empty?
   end
@@ -186,7 +209,7 @@ module DTAS::Source::AvFfCommon # :nodoc:
 
     e["PROBE"] = @probe_harder ? @probe_harder.join(' ') : nil
     # make sure these are visible to the source command...
-    e["INFILE"] = xs(@infile)
+    e["INFILE"] = @infile
     e["AMAP"] = amap
     e["SSPOS"] = sspos
     e["RGFX"] = rg_state.effect(self) || nil
diff --git a/lib/dtas/source/cmd.rb b/lib/dtas/source/cmd.rb
index cdcd3b3..435ac07 100644
--- a/lib/dtas/source/cmd.rb
+++ b/lib/dtas/source/cmd.rb
@@ -1,4 +1,4 @@
-# Copyright (C) 2013-2016 all contributors <dtas-all@nongnu.org>
+# Copyright (C) 2013-2020 all contributors <dtas-all@nongnu.org>
 # License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
 # frozen_string_literal: true
 require_relative '../../dtas'
diff --git a/lib/dtas/source/common.rb b/lib/dtas/source/common.rb
index a6d1a60..bdcb16d 100644
--- a/lib/dtas/source/common.rb
+++ b/lib/dtas/source/common.rb
@@ -1,4 +1,4 @@
-# Copyright (C) 2013-2016 all contributors <dtas-all@nongnu.org>
+# Copyright (C) 2013-2020 all contributors <dtas-all@nongnu.org>
 # License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
 module DTAS::Source::Common # :nodoc:
   attr_reader :dst_zero_byte # first byte this source object saw
diff --git a/lib/dtas/source/ff.rb b/lib/dtas/source/ff.rb
index 80436c7..c337b42 100644
--- a/lib/dtas/source/ff.rb
+++ b/lib/dtas/source/ff.rb
@@ -1,12 +1,10 @@
-# Copyright (C) 2013-2016 all contributors <dtas-all@nongnu.org>
+# Copyright (C) all contributors <dtas-all@nongnu.org>
 # License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
 # frozen_string_literal: true
 require_relative '../../dtas'
 require_relative 'av_ff_common'
 
 # ffmpeg support
-# note: only tested with the compatibility wrapper in the Debian 7.0 package
-# (so still using avconv/avprobe)
 class DTAS::Source::Ff  # :nodoc:
   include DTAS::Source::AvFfCommon
 
@@ -15,12 +13,12 @@ class DTAS::Source::Ff  # :nodoc:
       'ffmpeg -v error $SSPOS $PROBE -i "$INFILE" $AMAP -f sox - |' \
       'sox -p $SOXFMT - $TRIMFX $RGFX',
 
-    # I haven't tested this much since av is in Debian stable and ff is not
-    "tryorder" => 2,
+    "tryorder" => 1,
   )
 
   def initialize
     command_init(FF_DEFAULTS)
+    @mcache = nil
     @av_ff_probe = "ffprobe"
   end
 
diff --git a/lib/dtas/source/file.rb b/lib/dtas/source/file.rb
index 01ac998..88beb39 100644
--- a/lib/dtas/source/file.rb
+++ b/lib/dtas/source/file.rb
@@ -1,4 +1,4 @@
-# Copyright (C) 2013-2016 all contributors <dtas-all@nongnu.org>
+# Copyright (C) 2013-2020 all contributors <dtas-all@nongnu.org>
 # License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
 # frozen_string_literal: true
 require_relative '../../dtas'
diff --git a/lib/dtas/source/mp3gain.rb b/lib/dtas/source/mp3gain.rb
index 3a7569d..7688822 100644
--- a/lib/dtas/source/mp3gain.rb
+++ b/lib/dtas/source/mp3gain.rb
@@ -1,4 +1,4 @@
-# Copyright (C) 2013-2016 all contributors <dtas-all@nongnu.org>
+# Copyright (C) 2013-2020 all contributors <dtas-all@nongnu.org>
 # License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
 # frozen_string_literal: true
 require_relative '../process'
diff --git a/lib/dtas/source/sox.rb b/lib/dtas/source/sox.rb
index dc23c27..365c7b6 100644
--- a/lib/dtas/source/sox.rb
+++ b/lib/dtas/source/sox.rb
@@ -1,4 +1,4 @@
-# Copyright (C) 2013-2019 all contributors <dtas-all@nongnu.org>
+# Copyright (C) all contributors <dtas-all@nongnu.org>
 # License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
 # frozen_string_literal: true
 # encoding: binary
@@ -24,7 +24,7 @@ class DTAS::Source::Sox # :nodoc:
     return if @last_failed == infile
     @last_failed = infile
     case msg
-    when Process::Status then msg = "failed with #{msg.exitstatus}"
+    when Process::Status then msg = "failed with #{msg.inspect}"
     when 0 then msg = 'detected zero samples'
     end
     warn("soxi #{infile}: #{msg}\n")
@@ -39,7 +39,8 @@ class DTAS::Source::Sox # :nodoc:
   def mcache_lookup(infile)
     (@mcache ||= DTAS::Mcache.new).lookup(infile) do |input, dst|
       err = ''.b
-      out = qx(@env.dup, %W(soxi #{input}), err_str: err, no_raise: true)
+      out = qx(@env.dup, %W(soxi #{input}), err_str: err, no_raise: true,
+                rlimit_cpu: [ 1, 2 ])
       return soxi_failed(infile, out) if Process::Status === out
       return soxi_failed(infile, err) if err =~ /soxi FAIL formats:/
       out =~ /^Duration\s*:[^=]*= (\d+) samples /n
@@ -56,14 +57,14 @@ class DTAS::Source::Sox # :nodoc:
         key = nil
         $1.split(/\n/n).each do |line|
           if line.sub!(/^([^=]+)=/ni, '')
-            key = DTAS.dedupe_str(DTAS.try_enc($1.upcase, enc))
+            key = DTAS.try_enc($1.upcase, enc)
           end
           (comments[key] ||= ''.b) << "#{line}\n" unless line.empty?
         end
         comments.each do |k,v|
           v.chomp!
           DTAS.try_enc(v, enc)
-          comments[k] = DTAS.dedupe_str(v)
+          comments[k] = -v
         end
       end
       dst
@@ -113,7 +114,7 @@ class DTAS::Source::Sox # :nodoc:
   def src_spawn(player_format, rg_state, opts)
     raise "BUG: #{self.inspect}#src_spawn called twice" if @to_io
     e = @env.merge!(player_format.to_env)
-    e["INFILE"] = xs(@infile)
+    e["INFILE"] = @infile
 
     # make sure these are visible to the "current" command...
     e["TRIMFX"] = trimfx
diff --git a/lib/dtas/source/splitfx.rb b/lib/dtas/source/splitfx.rb
index f746bee..2268404 100644
--- a/lib/dtas/source/splitfx.rb
+++ b/lib/dtas/source/splitfx.rb
@@ -1,7 +1,6 @@
-# Copyright (C) 2014-2016 all contributors <dtas-all@nongnu.org>
+# Copyright (C) all contributors <dtas-all@nongnu.org>
 # License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
 # frozen_string_literal: true
-require 'yaml'
 require_relative 'sox'
 require_relative '../splitfx'
 require_relative '../watchable'
@@ -36,7 +35,7 @@ class DTAS::Source::SplitFX < DTAS::Source::Sox # :nodoc:
 
     sfx = DTAS::SplitFX.new
     Dir.chdir(File.dirname(ymlfile)) do # ugh
-      @ymlhash = YAML.load(buf)
+      @ymlhash = DTAS.yaml_load(buf)
       @ymlhash['tracks'] ||= [ "t 0 default" ]
       sfx.import(@ymlhash)
       sfx.infile.replace(File.expand_path(sfx.infile))