arquivo 0.2.2 → 0.2.3

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: ed65dd3f514e1950093d139e190ba9104037dc1637f4aa63a879aa5a26e7707f
4
- data.tar.gz: 75603c49ac01b58575ad63bba4aee0cf5265594fa41a95407aaa10125a717cf4
3
+ metadata.gz: cb7ecf71153002b263d88303a43e2c298d9afc9a25bf1ff996c18016c60dc6eb
4
+ data.tar.gz: 9304605a85684d6572891709c48082bf730d38ddc8c273a614ad5052a04596c3
5
5
  SHA512:
6
- metadata.gz: 2440e3fa68fbc48bc7e34432bcbb0d832d6c530c3dbbe872b649cb9f7c6d830b7e04034621b8dbbc8a2ad506abce5587394b6334c324f9c1932fd0f09cdca2d4
7
- data.tar.gz: dc20b52f6c192f51922637b96ebc8cc063178ce5812a8947aa0cc1f13c395cbba8698a0810d4269e70af9693cbbaf72ce54905726a46c74c8c958e7615a9a536
6
+ metadata.gz: 00aaddf208d5ab5123858c2ea52105b2c18495e35e398059c17b982a082fcdc80762a5d6d8f75bfa43e2cc5faeb6b0b68fc7ec05c91934e1620e35f6eec4a36f
7
+ data.tar.gz: 2c5f2f72098327bc4fee7df75281e5a55ded17058af3af633527750ecc04250ede81f4b06bb575d2be9b0854b73834ec10d44dfa2f1b1ed142d2c7eb02a9cc6e
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- arquivo (0.2.2)
4
+ arquivo (0.2.3)
5
5
  fastimage (~> 2.1)
6
6
  google-api-client (~> 0.34)
7
7
  pdf-reader (~> 2.3)
@@ -49,7 +49,7 @@ GEM
49
49
  hashery (~> 2.0)
50
50
  ruby-rc4
51
51
  ttfunk
52
- public_suffix (4.0.1)
52
+ public_suffix (4.0.2)
53
53
  rake (10.5.0)
54
54
  representable (3.0.4)
55
55
  declarative (< 0.1.0)
@@ -76,7 +76,7 @@ module Arquivo
76
76
  def dir(pasta)
77
77
  return unless File.ftype(pasta) == 'directory'
78
78
 
79
- C118dir.new(pasta, options).processa_pasta(pasta)
79
+ C118dir.new(pasta, options).processa_pasta
80
80
  end
81
81
  end
82
82
  end
@@ -7,21 +7,15 @@ require 'googleauth/stores/file_token_store'
7
7
  require 'arquivo/noise'
8
8
 
9
9
  module Arquivo
10
- # O1 = '2>/dev/null'
11
- # O2 = '1>/dev/null 2>&1'
12
- O1 = ''
13
- O2 = ''
14
- AT = ['.mp3', '.m4a', '.wav', '.sox'].freeze
15
-
16
10
  # permite processar e arquivar pasta com documentos c118
17
11
  class C118dir < Enumerator
18
12
  # @!group processamento
19
- # processa items duma pasta - sub-pastas recursivamente
13
+ # processa items duma pasta
20
14
  def processa_items
21
15
  n = 0
22
16
  while next_item
23
17
  if File.ftype(item) == 'directory'
24
- C118dir.new(item, opcoes).processa_pasta(item)
18
+ C118dir.new(item, opcoes).processa_pasta
25
19
  else
26
20
  processa_file(File.extname(item).downcase)
27
21
  n += 1
@@ -36,16 +30,16 @@ module Arquivo
36
30
  def processa_fim(num)
37
31
  return unless num.positive?
38
32
 
39
- cmd = if /minuta/i.match?(base)
40
- "rm -f #{base}.*"
33
+ cmd = if contem == :fsg
34
+ "rm -f #{nome}.*;sox tmp/zip/* #{nome}.mp3"
41
35
  else
42
- "rm -f #{base}.*;pdftk tmp/stamped*.pdf cat output #{base}.pdf"
36
+ "rm -f #{nome}.*;pdftk tmp/stamped* cat output #{nome}.pdf"
43
37
  end
44
- system cmd + ";cd tmp/zip;tar cf ../../#{base}.tar *" \
45
- ";cd ../..;gzip --best #{base}.tar" \
46
- '' # ';rm -rf tmp'
38
+ system cmd + ";cd tmp/zip;tar cf ../../#{nome}.tar *" \
39
+ ";cd ../..;gzip --best #{nome}.tar" \
40
+ ';rm -rf tmp'
47
41
 
48
- puts "#{base} (#{num})"
42
+ puts "#{nome} (#{num})"
49
43
  end
50
44
 
51
45
  # processa ficheiro JPG, PDF ou AUDIO
@@ -63,13 +57,11 @@ module Arquivo
63
57
  end
64
58
 
65
59
  # processa conteudo duma pasta
66
- #
67
- # @param pasta (see CLI#dir)
68
- def processa_pasta(pasta)
69
- unless File.ftype(items.peek) == 'directory'
60
+ def processa_pasta
61
+ if contem
70
62
  system 'mkdir -p tmp/zip'
71
- obtem_dados(pasta)
72
- obtem_noiseprof(pasta)
63
+ obtem_dados
64
+ obtem_noiseprof
73
65
  end
74
66
  processa_items
75
67
  end
@@ -82,19 +74,16 @@ module Arquivo
82
74
  end
83
75
 
84
76
  # @!group dados online
85
- # @param pasta (see CLI#dir)
86
77
  # @return [Hash] dados oficiais para reclassificacao de faturas e recibos
87
- def obtem_dados(pasta)
78
+ def obtem_dados
88
79
  @dados = {}
89
80
  # somente faturas e recibos necessitam reclassificacao
90
- return unless /fac?tura/i.match?(pasta) || /recibo/i.match?(pasta)
81
+ return unless %i[fft frc].include?(contem)
91
82
 
92
83
  # sheet c118-contas
93
84
  dg = '1PbiMrtTtqGztZMhe3AiJbDS6NQE9o3hXebnQEFdt954'
94
- # range dos dados (faturas/recibos)
95
- sh = (/fac?tura/i.match?(pasta) ? 'rft' : 'rrc') + '!A2:E'
96
- @dados = c118_sheets.get_spreadsheet_values(dg, sh).values
97
- .group_by { |k| k[0][/\w+/] }
85
+ @dados = c118_sheets.get_spreadsheet_values(dg, contem.to_s + '!A2:E')
86
+ .values.group_by { |k| k[0][/\w+/] }
98
87
  rescue StandardError
99
88
  @dados = {}
100
89
  end
@@ -101,7 +101,7 @@ module Arquivo
101
101
 
102
102
  @paginas = []
103
103
  n = pagina.scan(%r{N\. *(\d+)/(\d+)}).flatten
104
- @nome = n.empty? ? nil : "ex#{n[0][/\d{2}$/]}#{n[1]}"
104
+ @nome = n.empty? ? nil : "ex#{n[1]}-#{n[0]}"
105
105
  rescue StandardError
106
106
  @nome = nil
107
107
  end
@@ -3,7 +3,7 @@
3
3
  require 'fastimage'
4
4
 
5
5
  module Arquivo
6
- # size limit after trim attempt
6
+ # tipos de audio que consigo processa
7
7
  LT = 9000
8
8
 
9
9
  # A4 page (8.27x11.69) inches
@@ -54,18 +54,28 @@ module Arquivo
54
54
  apara.pdf.final(dad[id]).marca
55
55
  end
56
56
 
57
- # @return [C118jpg] jpg com melhor aparado
57
+ # @return [C118jpg] jpg com melhor aparo
58
58
  def apara
59
- f = opcoes[:fuzz]
60
- h = {}
61
- # aparar borders ao maximo
62
- while f >= 1
63
- o = "tmp/#{id}-#{f}.jpg"
64
- h[o] = size_aparado(f, o)
65
- f -= 4
66
- end
67
- m = h.min_by { |_, v| v }
68
- m[1].between?(LT, size) ? C118jpg.new(m[0], opcoes) : self
59
+ system cmd_apara(opcoes[:fuzz], '')
60
+ melhor_aparo
61
+ end
62
+
63
+ # @return (see #apara)
64
+ def melhor_aparo
65
+ m = Dir.glob("tmp/#{id}-*.jpg")
66
+ .map { |s| [s, File.size(s)] }
67
+ .min_by { |_, v| v.between?(LT, size) ? v : size }
68
+ m[1] < size ? C118jpg.new(m[0], opcoes) : self
69
+ end
70
+
71
+ # @return [String] comando para aparar imagem
72
+ def cmd_apara(fuzz, cmd)
73
+ return cmd[1..-1] unless fuzz >= 1
74
+
75
+ cmd += ";convert \"#{file}\" -fuzz #{fuzz}% -trim +repage " \
76
+ "#{oqualidade} tmp/#{id}-#{fuzz}.jpg #{O2}"
77
+
78
+ cmd_apara(fuzz - 4, cmd)
69
79
  end
70
80
 
71
81
  # @return [C118pdf] pdf com jpg processada dentro
@@ -76,15 +86,6 @@ module Arquivo
76
86
  C118pdf.new("tmp/#{id}-trimed.pdf", opcoes)
77
87
  end
78
88
 
79
- # @param [Numeric] fuzz fuzziness actual em processamento
80
- # @param [String] out jpg aparada
81
- # @return [Numeric] tamanho da jpg aparada
82
- def size_aparado(fuzz, out)
83
- system "convert \"#{file}\" -fuzz #{fuzz}% -trim +repage " \
84
- "#{oqualidade} #{out} #{O2}"
85
- File.size(out)
86
- end
87
-
88
89
  # @return [String] opcoes comprimir jpg
89
90
  def oqualidade
90
91
  "-quality #{opcoes[:quality]}% -compress jpeg"
@@ -60,7 +60,7 @@ module Arquivo
60
60
  # @param [Integer] pse numero do segmento em processamento
61
61
  # @return [String] nome do segmento
62
62
  def nome_segmento(pse)
63
- "s#{format('%<v>02d', v: pse)}-#{base[/\d{8}/]}#{base[/-\w+/]}"
63
+ "sg#{format('%<v>02d', v: pse)}-#{base[/\d{8}/]}#{base[/-\w+/]}"
64
64
  end
65
65
 
66
66
  # @param tempos (see #segmenta_minuta)
@@ -1,17 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Arquivo
4
+ O1 = '2>/dev/null'
5
+ O2 = '1>/dev/null 2>&1'
6
+ # tipos de audio que consigo processar
7
+ AT = %w[.mp3 .m4a .wav .sox].freeze
8
+ # tipos de documentos validos
9
+ # @example contem (see C118dir#obtem_conteudo)
10
+ DT = %i[fsc fsg frc fft fex].freeze
11
+
4
12
  # permite processar e arquivar pasta com documentos c118
5
13
  class C118dir < Enumerator
14
+ # @return [String] local da pasta
15
+ attr_reader :local
6
16
  # @return [Enumerator] items dentro duma pasta
7
17
  attr_reader :items
8
- # @return [String] base nome ficheiros para arquivo (pdf, tar.gz)
9
- attr_reader :base
18
+ # @return [String] nome ficheiro de arquivo
19
+ attr_reader :nome
10
20
  # @return [Hash] parametrizar JPG, MINUTA
11
21
  attr_reader :opcoes
22
+ # @return [Symbol] conteudo da pasta
23
+ attr_reader :contem
24
+
12
25
  # @return [String] documento c118
13
26
  attr_reader :item
14
-
15
27
  # @return (see #obtem_dados)
16
28
  attr_reader :dados
17
29
  # @return (see #obtem_noiseprof)
@@ -30,54 +42,77 @@ module Arquivo
30
42
  # @option opt [Numeric] :rate (16) sample rate - radio-16k, CD-44.1k,
31
43
  # PC-48k, pro-96k
32
44
  # @return [C118dir] pasta de documentos c118
33
- def initialize(pasta, opt)
34
- @items = Dir.glob(File.join(pasta, '*')).each
35
- @base = File.basename(pasta, File.extname(pasta)) + '-' +
45
+ def initialize(dir, opt)
46
+ c = Dir.glob(File.join(dir, '*'))
47
+ @local = dir
48
+ @items = c.each
49
+ @nome = File.basename(dir, File.extname(dir)) + '-' +
36
50
  Date.today.strftime('%Y%m%d')
37
51
  @opcoes = opt
52
+ @contem = obtem_conteudo(c)
53
+ end
54
+
55
+ # Agrupa conteudo duma pasta segundo tipos de documentos validos
56
+ #
57
+ # @param [Array] fls lista items duma pasta
58
+ # @return [Symbol] tipo de conteudo
59
+ # @example contem
60
+ # :fsc scq
61
+ # :fsg minutas
62
+ # :frc recibos
63
+ # :fft faturas
64
+ # :fex extratos
65
+ def obtem_conteudo(fls)
66
+ t = fls.group_by { |f| File.ftype(f)[0] + File.basename(f)[0, 2] }.keys
67
+ return unless t.size == 1 && DT.include?(t[0].to_sym)
68
+
69
+ t[0].to_sym
38
70
  end
39
71
 
40
72
  # @!group perfil silencio
41
- # @param pasta (see CLI#dir)
42
73
  # @return [String] perfil do maior silencio inicial de todos segmentos audio
43
- def obtem_noiseprof(pasta)
44
- return unless /minuta/i.match?(pasta)
74
+ def obtem_noiseprof
75
+ return unless contem == :fsg
45
76
 
46
- l = obtem_segmentos(pasta)
77
+ l = obtem_segmentos
47
78
  return unless l.size.positive?
48
79
 
49
80
  t = -1
50
81
  m = ['', 0]
51
- m = obtem_maximo_silencio(l, t += 1) while noisy?(m, t)
82
+ m = maximo_silencio(l, t += 1) while noisy?(m[1], t)
52
83
 
53
84
  cria_noiseprof(m)
54
85
  end
55
86
 
56
- # @param [Array<String, Float>] seg segmento, duracao silencio inicial
57
- # @param thr (see #obtem_maximo_silencio)
87
+ # @param [Float] duracao silencio
88
+ # @param thr (see #maximo_silencio)
58
89
  # @return [Boolean] segmento audio tem som ou silencio no inicio
59
- def noisy?(seg, thr)
60
- thr < opcoes[:threshold] && seg[1] <= opcoes[:sound]
90
+ def noisy?(sin, thr)
91
+ thr < opcoes[:threshold] && sin <= opcoes[:sound]
61
92
  end
62
93
 
63
- # @param [Array] lsg lista segmentos audio com duracoes
94
+ # @param [Array] lsg lista segmentos audio com duracoes e file silencio
64
95
  # @param [Numeric] thr limiar para silencio em processamento
65
96
  # @return [Array<String, Float>] segmento com maior duracao silencio inicial
66
- def obtem_maximo_silencio(lsg, thr)
67
- lsg.sort.map { |e| obtem_silencio(e, thr) }.max_by { |_, s| s }
97
+ def maximo_silencio(lsg, thr)
98
+ system lsg.inject('') { |s, e| s + cmd_silencio(e, thr) }[1..-1]
99
+ lsg.map { |e| [e[0], duracao_silencio(e)] }.max_by { |_, s| s }
68
100
  end
69
101
 
70
- # @param [Array<String, Float>] seg segmento audio, duracao
71
- # @param thr (see #obtem_maximo_silencio)
72
- # @return [Array<String, Float>] segmento audio, duracao silencio inicial
73
- def obtem_silencio(seg, thr)
74
- o = "tmp/thr-#{File.basename(seg[0])}"
75
- system "sox #{seg[0]} #{o} silence 1 #{opcoes[:sound]}t #{thr}% #{O2}"
102
+ # @param [Array<String, Float, String>] seg segmento, duracao, file silencio
103
+ # @param thr (see #maximo_silencio)
104
+ # @return [String] comando para cortar silencio inicial sum segmento
105
+ def cmd_silencio(seg, thr)
106
+ ";sox #{seg[0]} #{seg[2]} silence 1 #{opcoes[:sound]}t #{thr}% #{O2}"
107
+ end
76
108
 
77
- [seg[0], (seg[1] - duracao(o)).round(2, half: :down)]
109
+ # @param seg (see #cmd_silencio)
110
+ # @return [Float] duracao silencio em segundos
111
+ def duracao_silencio(seg)
112
+ (seg[1] - duracao(seg[2])).round(2, half: :down)
78
113
  end
79
114
 
80
- # @param seg (see #noisy?)
115
+ # @param [Array<String, Float>] seg segmento, duracao silencio inicial
81
116
  # @return [String] perfil sonoro do silencio inicial dum segmento
82
117
  def cria_noiseprof(seg)
83
118
  return unless seg[1] > opcoes[:sound]
@@ -90,11 +125,10 @@ module Arquivo
90
125
  @noiseprof = File.size?(o).positive? ? o : nil
91
126
  end
92
127
 
93
- # @param pasta (see CLI#dir)
94
- # @return [Array] lista segmentos audio com duracoes
95
- def obtem_segmentos(pasta)
96
- AT.map { |e| Dir.glob(File.join(pasta, 's[0-9][0-9]-*' + e)) }.flatten
97
- .map { |s| [s, duracao(s)] }
128
+ # @return [Array] lista segmentos audio com duracoes e file silencio
129
+ def obtem_segmentos
130
+ AT.map { |e| Dir.glob(File.join(local, 'sg*' + e)) }.flatten
131
+ .map { |s| [s, duracao(s), "tmp/thr-#{File.basename(s)}"] }
98
132
  end
99
133
 
100
134
  # @param [String] audio ficheiro de audio
@@ -121,7 +121,7 @@ module Arquivo
121
121
  return false if id[0] == 'r'
122
122
 
123
123
  o = "tmp/#{id}.txt"
124
- # se pdf contem texto -> not scanned
124
+ # se pdf contem texto -> not scanned pdf
125
125
  system "pdftotext -q -eol unix -nopgbrk \"#{file}\" #{o}"
126
126
  return false if File.size?(o)
127
127
 
@@ -129,6 +129,7 @@ module Arquivo
129
129
  # utilizar somente 1 imagem, comvertida em jpg
130
130
  system "convert #{Dir.glob("tmp/#{id}-???.???")[0]} #{jpg} #{O2}"
131
131
 
132
+ # jpg demasiado pequeno -> not scanned pdf
132
133
  File.size?(jpg) > LT
133
134
  end
134
135
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Arquivo
4
- VERSION = '0.2.2'
4
+ VERSION = '0.2.3'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: arquivo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hernâni Rodrigues Vaz
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-12-28 00:00:00.000000000 Z
11
+ date: 2019-12-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler