evideo 0.2.4 → 0.2.5
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/.rubocop.yml +12 -0
- data/.travis.yml +6 -0
- data/Gemfile.lock +58 -2
- data/README.md +10 -10
- data/Rakefile +5 -2
- data/evideo.gemspec +18 -13
- data/exe/ev +1 -1
- data/exe/evideo +1 -1
- data/lib/evideo.rb +25 -21
- data/lib/evideo/processa.rb +103 -0
- data/lib/evideo/vars1.rb +95 -0
- data/lib/evideo/vars2.rb +83 -0
- data/lib/evideo/version.rb +2 -1
- metadata +51 -6
- data/lib/evideo/hrvideo.rb +0 -93
- data/lib/evideo/hrvprocessa.rb +0 -131
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f5c77658b5bcd0344f7eff6ab91922381d9d49eccd003b29244b363c9b43502
|
4
|
+
data.tar.gz: b19c5ff8dd141e15cb19c41f2ea0a927a3c3d773b64ffe4a4e99c52f1d8d5556
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 62f8ae5efa2db98752f862eec528ef809efd86c76ac71117bfcffeeaaebee104a5af7cf9cf6f26cb9d2660f3ad04d7880bd38ee784ce1a371efd0d2c2307ca4b
|
7
|
+
data.tar.gz: e618be2769fce85c76319c7c72e5b7612164892a5a85e7e9d01a658a188249dfc47abed78af3e4fb355f16b1eabacb17f650af81bcdccd8600fe033de65fefe4
|
data/.rubocop.yml
ADDED
data/.travis.yml
ADDED
data/Gemfile.lock
CHANGED
@@ -1,14 +1,67 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
evideo (0.2.
|
4
|
+
evideo (0.2.5)
|
5
5
|
thor
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
+
ast (2.4.1)
|
11
|
+
backport (1.1.2)
|
12
|
+
benchmark (0.1.0)
|
13
|
+
e2mmap (0.1.0)
|
14
|
+
jaro_winkler (1.5.4)
|
15
|
+
kwalify (0.7.2)
|
16
|
+
maruku (0.7.3)
|
17
|
+
mini_portile2 (2.4.0)
|
18
|
+
nokogiri (1.10.10)
|
19
|
+
mini_portile2 (~> 2.4.0)
|
20
|
+
parallel (1.19.2)
|
21
|
+
parser (2.7.2.0)
|
22
|
+
ast (~> 2.4.1)
|
23
|
+
psych (3.2.0)
|
24
|
+
rainbow (3.0.0)
|
10
25
|
rake (13.0.1)
|
26
|
+
reek (6.0.2)
|
27
|
+
kwalify (~> 0.7.0)
|
28
|
+
parser (>= 2.5.0.0, < 2.8, != 2.5.1.1)
|
29
|
+
psych (~> 3.1)
|
30
|
+
rainbow (>= 2.0, < 4.0)
|
31
|
+
regexp_parser (1.8.2)
|
32
|
+
reverse_markdown (2.0.0)
|
33
|
+
nokogiri
|
34
|
+
rexml (3.2.4)
|
35
|
+
rubocop (0.93.1)
|
36
|
+
parallel (~> 1.10)
|
37
|
+
parser (>= 2.7.1.5)
|
38
|
+
rainbow (>= 2.2.2, < 4.0)
|
39
|
+
regexp_parser (>= 1.8)
|
40
|
+
rexml
|
41
|
+
rubocop-ast (>= 0.6.0)
|
42
|
+
ruby-progressbar (~> 1.7)
|
43
|
+
unicode-display_width (>= 1.4.0, < 2.0)
|
44
|
+
rubocop-ast (1.0.0)
|
45
|
+
parser (>= 2.7.1.5)
|
46
|
+
ruby-progressbar (1.10.1)
|
47
|
+
solargraph (0.39.17)
|
48
|
+
backport (~> 1.1)
|
49
|
+
benchmark
|
50
|
+
bundler (>= 1.17.2)
|
51
|
+
e2mmap
|
52
|
+
jaro_winkler (~> 1.5)
|
53
|
+
maruku (~> 0.7, >= 0.7.3)
|
54
|
+
nokogiri (~> 1.9, >= 1.9.1)
|
55
|
+
parser (~> 2.3)
|
56
|
+
reverse_markdown (>= 1.0.5, < 3)
|
57
|
+
rubocop (~> 0.52)
|
58
|
+
thor (~> 1.0)
|
59
|
+
tilt (~> 2.0)
|
60
|
+
yard (~> 0.9, >= 0.9.24)
|
11
61
|
thor (1.0.1)
|
62
|
+
tilt (2.0.10)
|
63
|
+
unicode-display_width (1.7.0)
|
64
|
+
yard (0.9.25)
|
12
65
|
|
13
66
|
PLATFORMS
|
14
67
|
ruby
|
@@ -17,6 +70,9 @@ DEPENDENCIES
|
|
17
70
|
bundler
|
18
71
|
evideo!
|
19
72
|
rake
|
73
|
+
reek
|
74
|
+
rubocop
|
75
|
+
solargraph
|
20
76
|
|
21
77
|
BUNDLED WITH
|
22
|
-
2.1.
|
78
|
+
2.1.4
|
data/README.md
CHANGED
@@ -8,16 +8,16 @@ Processa ficheiros video. Pode alterar bitrate, framerate, height, aspect ratio
|
|
8
8
|
|
9
9
|
## Usage
|
10
10
|
|
11
|
-
$ ev conv
|
12
|
-
$ ev test
|
11
|
+
$ ev conv # converte videos
|
12
|
+
$ ev test # testa videos
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
14
|
+
opcoes:
|
15
|
+
[-d=DIR] # Onde procurar videos defeito: ["/home/eu/lust", "/media/eu/hrv2", "/media/eu/hrv2/lust"]
|
16
|
+
[-i=IN] # Pasta inicial defeito: ftv
|
17
|
+
[-o=OUT] # Pasta final defeito: out
|
18
|
+
[-x], [--no-x] # executa/mostra comando converte videos
|
19
|
+
[-s=N] # Segundos cortados no inicio do video final defeito: 0=sem cortes
|
20
|
+
[-t=N] # Segundos duracao video final defeito: 0=sem cortes
|
21
21
|
|
22
22
|
## Development
|
23
23
|
|
@@ -27,7 +27,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
27
27
|
|
28
28
|
## Contributing
|
29
29
|
|
30
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
30
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/hernanilr/evideo.
|
31
31
|
|
32
32
|
## License
|
33
33
|
|
data/Rakefile
CHANGED
data/evideo.gemspec
CHANGED
@@ -5,15 +5,16 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
5
5
|
require 'evideo/version'
|
6
6
|
|
7
7
|
Gem::Specification.new do |spec|
|
8
|
-
spec.name
|
9
|
-
spec.version
|
10
|
-
spec.authors
|
11
|
-
spec.email
|
12
|
-
spec.homepage
|
13
|
-
spec.license
|
8
|
+
spec.name = 'evideo'
|
9
|
+
spec.version = Evideo::VERSION
|
10
|
+
spec.authors = ['Hernâni Rodrigues Vaz']
|
11
|
+
spec.email = ['hernanirvaz@gmail.com']
|
12
|
+
spec.homepage = 'https://github.com/hernanilr/evideo'
|
13
|
+
spec.license = 'MIT'
|
14
|
+
spec.required_ruby_version = '~> 2.7'
|
14
15
|
|
15
16
|
spec.summary = 'Processa ficheiros video.'
|
16
|
-
spec.description = spec.summary
|
17
|
+
spec.description = "#{spec.summary} Pode alterar bitrate, framerate, height, aspect ratio e elimina metadata."
|
17
18
|
|
18
19
|
spec.metadata['homepage_uri'] = spec.homepage
|
19
20
|
spec.metadata['yard.run'] = 'yard'
|
@@ -21,15 +22,19 @@ Gem::Specification.new do |spec|
|
|
21
22
|
# Specify which files should be added to the gem when it is released.
|
22
23
|
# The `git ls-files -z` loads the files in the RubyGem that have been
|
23
24
|
# added into git.
|
24
|
-
spec.files =
|
25
|
-
|
26
|
-
|
25
|
+
spec.files =
|
26
|
+
Dir.chdir(File.expand_path(__dir__)) do
|
27
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
28
|
+
end
|
27
29
|
spec.bindir = 'exe'
|
28
30
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
29
31
|
spec.require_paths = ['lib']
|
30
32
|
|
31
|
-
spec.add_development_dependency
|
32
|
-
spec.add_development_dependency
|
33
|
+
spec.add_development_dependency('bundler')
|
34
|
+
spec.add_development_dependency('rake')
|
35
|
+
spec.add_development_dependency('reek')
|
36
|
+
spec.add_development_dependency('rubocop')
|
37
|
+
spec.add_development_dependency('solargraph')
|
33
38
|
|
34
|
-
spec.add_dependency
|
39
|
+
spec.add_dependency('thor')
|
35
40
|
end
|
data/exe/ev
CHANGED
data/exe/evideo
CHANGED
data/lib/evideo.rb
CHANGED
@@ -1,45 +1,49 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'thor'
|
4
|
+
require 'evideo/vars1'
|
5
|
+
require 'evideo/vars2'
|
6
|
+
require 'evideo/processa'
|
4
7
|
require 'evideo/version'
|
5
|
-
require 'evideo/hrvideo'
|
6
|
-
require 'evideo/hrvprocessa'
|
7
8
|
|
9
|
+
# (see Evideo)
|
8
10
|
module Evideo
|
9
|
-
|
10
|
-
|
11
|
+
who = `whoami`.chomp
|
12
|
+
ADI = ["/home/#{who}/lust", "/media/#{who}/hrv2", "/media/#{who}/hrv2/lust"].freeze
|
13
|
+
|
11
14
|
# CLI para analisar/processar videos
|
12
15
|
class CLI < Thor
|
13
|
-
class_option :d, banner: 'DIR', type: :array, desc: 'Onde procurar videos',
|
14
|
-
|
15
|
-
class_option :
|
16
|
-
class_option :o, banner: 'OUT', default: 'out', desc: 'Pasta destino'
|
16
|
+
class_option :d, banner: 'DIR', type: :array, desc: 'Onde procurar videos', default: ADI
|
17
|
+
class_option :i, banner: 'IN', default: 'ftv', desc: 'Pasta inicial'
|
18
|
+
class_option :o, banner: 'OUT', default: 'out', desc: 'Pasta final'
|
17
19
|
|
18
20
|
desc 'conv', 'converte videos'
|
19
|
-
option :
|
21
|
+
option :x, type: :boolean, default: false, desc: 'executa/mostra comando converte videos'
|
22
|
+
option :s, type: :numeric, default: 0, desc: 'Segundos cortados no inicio do video final 0=sem cortes'
|
23
|
+
option :t, type: :numeric, default: 0, desc: 'Segundos duracao video final 0=sem cortes'
|
24
|
+
# converte videos
|
20
25
|
def conv
|
21
|
-
|
22
|
-
|
26
|
+
# cria pasta final para videos processados
|
27
|
+
system("mkdir -p #{ipasta}/#{options[:o]}")
|
28
|
+
|
29
|
+
Dir.glob("#{ipasta}/*.???").sort.each do |file|
|
30
|
+
Video.new(file, options).processa
|
23
31
|
end
|
24
32
|
end
|
25
33
|
|
26
34
|
desc 'test', 'testa videos'
|
35
|
+
# testa videos
|
27
36
|
def test
|
28
|
-
Dir.glob("#{
|
29
|
-
|
37
|
+
Dir.glob("#{ipasta}/*.???").sort.each do |file|
|
38
|
+
puts(Video.new(file, options).inout)
|
30
39
|
end
|
31
40
|
end
|
32
41
|
|
33
42
|
default_task :test
|
34
43
|
no_commands do
|
35
|
-
# @return [String] pasta absoluta
|
36
|
-
def
|
37
|
-
"#{options[:d]
|
38
|
-
end
|
39
|
-
|
40
|
-
# @return [String] pasta absoluta destino dos videos
|
41
|
-
def fout
|
42
|
-
"#{options[:d].first}/#{options[:o]}"
|
44
|
+
# @return [String] pasta absoluta inicial dos videos
|
45
|
+
def ipasta
|
46
|
+
"#{options[:d][0]}/#{options[:i]}"
|
43
47
|
end
|
44
48
|
end
|
45
49
|
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# (see Evideo)
|
4
|
+
module Evideo
|
5
|
+
# aspect ratios a converter para 16:9
|
6
|
+
ART = ['0:1', '4:3'].freeze
|
7
|
+
|
8
|
+
# classe permite analizar/processar videos para arquivo uniformizado
|
9
|
+
class Video
|
10
|
+
# processa video - somente se necessario
|
11
|
+
def processa
|
12
|
+
return if ivideo? || opastas?
|
13
|
+
|
14
|
+
work(cmd_mpeg("#{ops[:d][0]}/#{ops[:i]}/#{ops[:o]}/#{bas.downcase}"))
|
15
|
+
end
|
16
|
+
|
17
|
+
# executa/mostra comando mpeg
|
18
|
+
# @param [String] cmd comando mpeg
|
19
|
+
def work(cmd)
|
20
|
+
if ops[:x]
|
21
|
+
puts("processar #{inout}")
|
22
|
+
system(cmd)
|
23
|
+
else
|
24
|
+
puts(cmd)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# @return [String] params video inicial & comando mpeg
|
29
|
+
def inout
|
30
|
+
"#{bas}#{ishow} OUT: #{fparams}"
|
31
|
+
end
|
32
|
+
|
33
|
+
# @return [true, false] video inicial ok
|
34
|
+
def ivideo?
|
35
|
+
return false if ext != '.mp4' || iaudio.positive? || ibitrate >= 3000 || iheight <= 480
|
36
|
+
|
37
|
+
puts("mv #{inome} #{onome} #{ishow}")
|
38
|
+
true
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [true, false] video final ok
|
42
|
+
def ovideo?
|
43
|
+
oinit
|
44
|
+
return false if Video.to_t(otempo, 5) != Video.to_t(itempo, 5) || obitrate >= 3000 || oheight < 480
|
45
|
+
|
46
|
+
puts("rm #{inome} #{oshow}")
|
47
|
+
true
|
48
|
+
end
|
49
|
+
|
50
|
+
# @return [true, false] pastas com video final ok
|
51
|
+
def opastas?
|
52
|
+
ary = ops[:d]
|
53
|
+
if pos == ary.size then false
|
54
|
+
elsif ovideo? then true
|
55
|
+
else
|
56
|
+
# proxima pasta
|
57
|
+
@pos += 1
|
58
|
+
opastas?
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# @return [String] parametros do comando processar video
|
63
|
+
def fparams
|
64
|
+
# frame rate & bitrate & dimensions & aspect ratio
|
65
|
+
"-r #{[ifps, 25.0].min} -b:v #{[ibitrate, 2000].min}k#{fdimensions}#{fratio}"
|
66
|
+
end
|
67
|
+
|
68
|
+
# @return [String] dimensions do comando processar video
|
69
|
+
def fdimensions
|
70
|
+
if iheight < 480 then ' -s hd480'
|
71
|
+
elsif iheight <= 720 then ' -s hd720'
|
72
|
+
else ' -s hd1080'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# @return [String] aspect ratio do comando processar video
|
77
|
+
def fratio
|
78
|
+
ART.include?(iratio) ? " -aspect 16:9 -filter:v 'pad=ih*16/9:ih:(ow-iw)/2:(oh-ih)/2'" : ''
|
79
|
+
end
|
80
|
+
|
81
|
+
# @return [String] cortes inicio video & duracao do video final processado
|
82
|
+
def fcuts
|
83
|
+
ict = Integer(ops[:s])
|
84
|
+
fct = Integer(ops[:t])
|
85
|
+
"#{ict.positive? ? " -ss #{ict}" : ''}#{fct.positive? ? " -t #{fct}" : ''}"
|
86
|
+
end
|
87
|
+
|
88
|
+
# @param [String] ficheiro video
|
89
|
+
# @return [String] comando probe
|
90
|
+
def cmd_prob(ficheiro)
|
91
|
+
"ffprobe -hide_banner -show_streams #{ficheiro} 2>&1|grep -v title"
|
92
|
+
end
|
93
|
+
|
94
|
+
# @param [String] base ficheiro video final
|
95
|
+
# @return [String] comando mpeg
|
96
|
+
def cmd_mpeg(base)
|
97
|
+
oout = "#{base}.out"
|
98
|
+
"ffmpeg -loglevel quiet -hide_banner -i #{inome} -y -an #{fparams}#{fcuts} "\
|
99
|
+
'-metadata title= -metadata artist= -metadata comment= -metadata major_brand= -metadata compatible_brands= '\
|
100
|
+
"#{base}.mp4 >#{oout} 2>&1;[ -s #{oout} ] || rm #{oout}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/lib/evideo/vars1.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# (see Evideo)
|
4
|
+
module Evideo
|
5
|
+
# parametros video :tempo, :bitrate - Duration: 01:01:08.50, start: 0.000000, bitrate: 2228 kb/s
|
6
|
+
RE1 = /duration:\s+(\d\d:\d\d:\d\d).*bitrate:\s+(\d+)\s+kb/i.freeze
|
7
|
+
# parametros video :height, :fps -
|
8
|
+
# Stream #0:0: Video: h264 (Main), yuv420p(tv, bt709, progressive), 1280x720
|
9
|
+
# [SAR 1:1 DAR 16:9], 23.98 fps, 23.98 tbr, 1k tbn, 180k tbc (default)
|
10
|
+
RE2 = /stream.*video:.*x\s*(\d+).*\s+(\d+\.*\d*)\s+fps/i.freeze
|
11
|
+
# parametros video :ratio - display_aspect_ratio=16:9
|
12
|
+
RE3 = /display_aspect_ratio\s*=\s*(\d+:\d+)$/i.freeze
|
13
|
+
# parametros video :audio - Stream #0:1(eng): Audio: aac (LC), 48000 Hz, stereo, fltp (default)
|
14
|
+
RE4 = /stream.*audio:.*\s+(\d+)\s+hz/i.freeze
|
15
|
+
|
16
|
+
# permite analizar string output do comando sonda video
|
17
|
+
class Video
|
18
|
+
# @return [String] base ficheiro video
|
19
|
+
attr_reader :bas
|
20
|
+
# @return [String] extensao ficheiro video
|
21
|
+
attr_reader :ext
|
22
|
+
# @return [Thor::CoreExt::HashWithIndifferentAccess] opcoes trabalho
|
23
|
+
attr_reader :ops
|
24
|
+
|
25
|
+
# @param [String] ficheiro video a processar
|
26
|
+
# @param [Thor::CoreExt::HashWithIndifferentAccess] opcoes trabalho
|
27
|
+
# @option opcoes [Array<String>] :d (/home/eu/lust,/media/eu/hrv2,/media/eu/hrv2/lust) pastas onde procurar videos
|
28
|
+
# @option opcoes [String] :i (ftv) pasta inicial dos videos
|
29
|
+
# @option opcoes [String] :o (out) pasta final dos videos
|
30
|
+
# @option opcoes [Boolean] :s (false) 10 segundos cortados no inicio do video final
|
31
|
+
# @option opcoes [Integer] :t (0) segundos duracao video final 0=sem cortes
|
32
|
+
# @return [Video] videos processados para arquivo uniformizado
|
33
|
+
def initialize(ficheiro, opcoes)
|
34
|
+
@ext = File.extname(ficheiro)
|
35
|
+
@bas = File.basename(ficheiro, ext)
|
36
|
+
@ops = opcoes
|
37
|
+
@iopcao = {}
|
38
|
+
end
|
39
|
+
|
40
|
+
# @return [String] texto probe do video inicial
|
41
|
+
def iprobe
|
42
|
+
@iprobe ||= `#{cmd_prob(inome)}`
|
43
|
+
end
|
44
|
+
|
45
|
+
# @return [Array<String>] parametros video inicial [:tempo, :bitrate]
|
46
|
+
def i1scan
|
47
|
+
@i1scan ||= iprobe.scan(RE1).flatten
|
48
|
+
end
|
49
|
+
|
50
|
+
# @return [Array<String>] parametros video inicial [:height, :fps]
|
51
|
+
def i2scan
|
52
|
+
@i2scan ||= iprobe.scan(RE2).flatten
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [String] parametro video inicial :tempo hh:mm:ss
|
56
|
+
def itempo
|
57
|
+
@iopcao[:tempo] ||= (i1scan[0] || '00:00:00')
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [Integer] parametro video inicial :bitrate kb/s
|
61
|
+
def ibitrate
|
62
|
+
@iopcao[:bitrate] ||= Integer(i1scan[1] || 0)
|
63
|
+
end
|
64
|
+
|
65
|
+
# @return [Integer] parametro video inicial :height
|
66
|
+
def iheight
|
67
|
+
@iopcao[:height] ||= Integer(i2scan[0] || 0)
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return [Float] parametro video inicial :fps frame_rate
|
71
|
+
def ifps
|
72
|
+
@iopcao[:fps] ||= Float(i2scan[1] || 0)
|
73
|
+
end
|
74
|
+
|
75
|
+
# @return [String] parametro video inicial aspect :ratio 16:9
|
76
|
+
def iratio
|
77
|
+
@iopcao[:ratio] ||= (iprobe.scan(RE3).flatten[0] || '0:1')
|
78
|
+
end
|
79
|
+
|
80
|
+
# @return [Integer] parametro video inicial :audio Hz
|
81
|
+
def iaudio
|
82
|
+
@iopcao[:audio] ||= Integer(iprobe.scan(RE4).flatten[0] || 0)
|
83
|
+
end
|
84
|
+
|
85
|
+
# @return [String] ficheiro inicial absoluto
|
86
|
+
def inome
|
87
|
+
"#{ops[:d][0]}/#{ops[:i]}/#{bas}#{ext}"
|
88
|
+
end
|
89
|
+
|
90
|
+
# @return [String] mostra dados do ficheiro video inicial
|
91
|
+
def ishow
|
92
|
+
"# r:#{ibitrate} h:#{iheight} #{iratio}"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
data/lib/evideo/vars2.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'time'
|
4
|
+
|
5
|
+
# (see Evideo)
|
6
|
+
module Evideo
|
7
|
+
# permite analizar string output do comando sonda video
|
8
|
+
class Video
|
9
|
+
# @return [Time] tempo no ruby standard library com precisao
|
10
|
+
def self.to_t(tempo, pre = 8)
|
11
|
+
Time.parse(tempo[0, pre])
|
12
|
+
end
|
13
|
+
|
14
|
+
# inicia variaveis do video final
|
15
|
+
def oinit
|
16
|
+
@oopcao = {}
|
17
|
+
@oprobe = nil
|
18
|
+
@o1scan = nil
|
19
|
+
@o2scan = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [String] texto probe do video final
|
23
|
+
def oprobe
|
24
|
+
return '' unless File.exist?(onome)
|
25
|
+
|
26
|
+
@oprobe ||= `#{cmd_prob(onome)}`
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [Array<String>] parametros video final [:tempo, :bitrate]
|
30
|
+
def o1scan
|
31
|
+
@o1scan ||= oprobe.scan(RE1).flatten
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [Array<String>] parametros video final [:height, :fps]
|
35
|
+
def o2scan
|
36
|
+
@o2scan ||= oprobe.scan(RE2).flatten
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [String] parametro video final :tempo hh:mm:ss
|
40
|
+
def otempo
|
41
|
+
@oopcao[:tempo] ||= (o1scan[0] || '00:00:00')
|
42
|
+
end
|
43
|
+
|
44
|
+
# @return [Integer] parametro video final :bitrate kb/s
|
45
|
+
def obitrate
|
46
|
+
@oopcao[:bitrate] ||= Integer(o1scan[1] || 0)
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [Integer] parametro video final :height
|
50
|
+
def oheight
|
51
|
+
@oopcao[:height] ||= Integer(o2scan[0] || 0)
|
52
|
+
end
|
53
|
+
|
54
|
+
# @return [Float] parametro video final :fps frame_rate
|
55
|
+
def ofps
|
56
|
+
@oopcao[:fps] ||= Float(o2scan[1] || 0)
|
57
|
+
end
|
58
|
+
|
59
|
+
# @return [String] parametro video final aspect :ratio 16:9
|
60
|
+
def oratio
|
61
|
+
@oopcao[:ratio] ||= (oprobe.scan(RE3).flatten[0] || '0:1')
|
62
|
+
end
|
63
|
+
|
64
|
+
# @return [Integer] posicao array pastas onde procurar videos finais
|
65
|
+
def pos
|
66
|
+
# -1 #{ops[:d][0]}/#{ops[:i]}/#{ops[:o]}"
|
67
|
+
# 0 #{ops[:d][pos]}/#{ops[:o]}"
|
68
|
+
# 1 #{ops[:d][pos]}/#{ops[:o]}"
|
69
|
+
@pos ||= -1
|
70
|
+
end
|
71
|
+
|
72
|
+
# @return [String] video final absoluto
|
73
|
+
def onome
|
74
|
+
dir = ops[:d]
|
75
|
+
(pos == -1 ? "#{dir[0]}/#{ops[:i]}" : dir[pos]) + "/#{ops[:o]}/#{bas.downcase}.mp4"
|
76
|
+
end
|
77
|
+
|
78
|
+
# @return [String] mostra dados do ficheiro video final
|
79
|
+
def oshow
|
80
|
+
"# r:#{obitrate} h:#{oheight} #{oratio} #{ops[:d][pos]}/#{ops[:o]}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/evideo/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: evideo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.5
|
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: 2020-
|
11
|
+
date: 2020-10-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -38,6 +38,48 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: reek
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rubocop
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: solargraph
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
41
83
|
- !ruby/object:Gem::Dependency
|
42
84
|
name: thor
|
43
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -63,6 +105,8 @@ extensions: []
|
|
63
105
|
extra_rdoc_files: []
|
64
106
|
files:
|
65
107
|
- ".gitignore"
|
108
|
+
- ".rubocop.yml"
|
109
|
+
- ".travis.yml"
|
66
110
|
- Gemfile
|
67
111
|
- Gemfile.lock
|
68
112
|
- LICENSE.txt
|
@@ -74,8 +118,9 @@ files:
|
|
74
118
|
- exe/ev
|
75
119
|
- exe/evideo
|
76
120
|
- lib/evideo.rb
|
77
|
-
- lib/evideo/
|
78
|
-
- lib/evideo/
|
121
|
+
- lib/evideo/processa.rb
|
122
|
+
- lib/evideo/vars1.rb
|
123
|
+
- lib/evideo/vars2.rb
|
79
124
|
- lib/evideo/version.rb
|
80
125
|
homepage: https://github.com/hernanilr/evideo
|
81
126
|
licenses:
|
@@ -89,9 +134,9 @@ require_paths:
|
|
89
134
|
- lib
|
90
135
|
required_ruby_version: !ruby/object:Gem::Requirement
|
91
136
|
requirements:
|
92
|
-
- - "
|
137
|
+
- - "~>"
|
93
138
|
- !ruby/object:Gem::Version
|
94
|
-
version: '
|
139
|
+
version: '2.7'
|
95
140
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
141
|
requirements:
|
97
142
|
- - ">="
|
data/lib/evideo/hrvideo.rb
DELETED
@@ -1,93 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Evideo
|
4
|
-
# permite analizar string output do comando sonda video
|
5
|
-
class HRVideo
|
6
|
-
# @return [String] nome do ficheiro video
|
7
|
-
attr_reader :nome
|
8
|
-
# @return [String] extensao do ficheiro video
|
9
|
-
attr_reader :ext
|
10
|
-
# @return [String] base do ficheiro video
|
11
|
-
attr_reader :base
|
12
|
-
# @return [String] duracao do ficheiro video
|
13
|
-
attr_reader :tempo
|
14
|
-
# @return [String] bitrate do ficheiro video
|
15
|
-
attr_reader :bitrate
|
16
|
-
|
17
|
-
# Duration: 01:01:08.50, start: 0.000000, bitrate: 2228 kb/s
|
18
|
-
R1 = /duration:\s+(\d\d:\d\d:\d\d).*bitrate:\s+(\d+)\s+kb/i.freeze
|
19
|
-
# Stream #0:0: Video: h264 (Main), yuv420p(tv, bt709, progressive), 1280x720
|
20
|
-
# [SAR 1:1 DAR 16:9], 23.98 fps, 23.98 tbr, 1k tbn, 180k tbc (default)
|
21
|
-
R2 = /stream.*video:.*x\s*(\d+).*\s+(\d+\.*\d*)\s+fps/i.freeze
|
22
|
-
# display_aspect_ratio=16:9
|
23
|
-
R3 = /display_aspect_ratio\s*=\s*(\d+:\d+)$/i.freeze
|
24
|
-
# Stream #0:1(eng): Audio: aac (LC), 48000 Hz, stereo, fltp (default)
|
25
|
-
# Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 127 kb/s (default)
|
26
|
-
R4 = /stream.*audio:.*\s+(\d+)\s+hz/i.freeze
|
27
|
-
|
28
|
-
def initialize(fil)
|
29
|
-
@nome = fil
|
30
|
-
@ext = File.extname(fil)
|
31
|
-
@base = File.basename(fil, @ext).downcase
|
32
|
-
@tempo = '00:00:00'
|
33
|
-
@bitrate = 0
|
34
|
-
@probe = `#{cmd_probe}` if File.exist?(fil)
|
35
|
-
return unless @probe
|
36
|
-
|
37
|
-
tr1 = @probe.scan(R1).flatten
|
38
|
-
@tempo = tr1[0].to_s
|
39
|
-
@bitrate = tr1[1].to_i
|
40
|
-
end
|
41
|
-
|
42
|
-
# Parametrizar height e frame rate
|
43
|
-
def r2
|
44
|
-
return unless @probe
|
45
|
-
|
46
|
-
tr2 = @probe.scan(R2).flatten
|
47
|
-
@height = tr2[0].to_i
|
48
|
-
@fps = tr2[1].to_f
|
49
|
-
end
|
50
|
-
|
51
|
-
# Parametrizar aspect ratio
|
52
|
-
def r3
|
53
|
-
return unless @probe
|
54
|
-
|
55
|
-
@ratio = @probe.scan(R3).flatten[0]
|
56
|
-
end
|
57
|
-
|
58
|
-
# Parametrizar audio
|
59
|
-
def r4
|
60
|
-
return unless @probe
|
61
|
-
|
62
|
-
@audio = @probe.scan(R4).flatten[0].to_i
|
63
|
-
end
|
64
|
-
|
65
|
-
# @return [String] audio
|
66
|
-
def audio
|
67
|
-
r4 unless @audio
|
68
|
-
|
69
|
-
@audio
|
70
|
-
end
|
71
|
-
|
72
|
-
# @return [String] height
|
73
|
-
def height
|
74
|
-
r2 unless @height
|
75
|
-
|
76
|
-
@height
|
77
|
-
end
|
78
|
-
|
79
|
-
# @return [String] frame rate
|
80
|
-
def fps
|
81
|
-
r2 unless @fps
|
82
|
-
|
83
|
-
@fps
|
84
|
-
end
|
85
|
-
|
86
|
-
# @return [String] aspect ratio
|
87
|
-
def ratio
|
88
|
-
r3 unless @ratio
|
89
|
-
|
90
|
-
@ratio
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
data/lib/evideo/hrvprocessa.rb
DELETED
@@ -1,131 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'time'
|
4
|
-
|
5
|
-
module Evideo
|
6
|
-
# permite analizar/processar videos para arquivo
|
7
|
-
class HRVideo
|
8
|
-
# @return [String] tempo: rate:
|
9
|
-
def show
|
10
|
-
return nome unless @probe
|
11
|
-
|
12
|
-
"tempo: #{tempo} rate: #{bitrate} ratio: #{ratio} height: #{height}"
|
13
|
-
end
|
14
|
-
|
15
|
-
# Testa validade video original
|
16
|
-
#
|
17
|
-
# @param [String] aot pasta destino dos videos absoluta
|
18
|
-
# @return [true, false] sim ou nao video original esta ok
|
19
|
-
def ofok?(aot)
|
20
|
-
return false unless processa_of?
|
21
|
-
|
22
|
-
puts "mv \"#{nome} #{aot}/#{base}.mp4\" # #{show}"
|
23
|
-
true
|
24
|
-
end
|
25
|
-
|
26
|
-
# @return [true, false] video original precisa ser processado?
|
27
|
-
def processa_of?
|
28
|
-
# prossecar somente videos grandes (>1 min) ou extensao errada ou bitrate >= 3000
|
29
|
-
((bitrate < 3000 && ext == '.mp4') || Time.parse(tempo) < Time.parse('00:01:00')) &&
|
30
|
-
# prossecar somente videos com ratio, height, audio errados
|
31
|
-
ratio == '16:9' && height > 480 && audio.zero?
|
32
|
-
end
|
33
|
-
|
34
|
-
# Testa validade video processado contra video original
|
35
|
-
#
|
36
|
-
# @param [String] hrv video processado a testar validade
|
37
|
-
# @return [true, false] sim ou nao video esta ok
|
38
|
-
def vfok?(hrv)
|
39
|
-
return false unless File.exist?(hrv.nome) && hrv.bitrate < 3000 && Time.parse(hrv.tempo) > Time.parse(tempo) - 60
|
40
|
-
|
41
|
-
puts "rm \"#{nome}\" # #{hrv.nome} #{hrv.show}"
|
42
|
-
true
|
43
|
-
end
|
44
|
-
|
45
|
-
# Testa validade videos processados em todos locais contra video original
|
46
|
-
#
|
47
|
-
# @param [Array<String>] ary array locais onde procurar videos
|
48
|
-
# @param [String] pot pasta destino dos videos
|
49
|
-
# @return [true, false] sim ou nao <local>/<video> esta ok
|
50
|
-
def vdok?(ary, pot)
|
51
|
-
if ary.empty? then false
|
52
|
-
elsif vfok?(HRVideo.new("#{ary.first}/#{pot}/#{base}.mp4")) then true
|
53
|
-
else vdok?(ary.drop(1), pot)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
# @return [String] aspect ratio comando conversao
|
58
|
-
def aspect
|
59
|
-
if ratio == '0:1' then height < 720 ? '' : ' -aspect 16:9'
|
60
|
-
else " -aspect #{ratio}"
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
# @return [String] video dimensions comando conversao
|
65
|
-
def dimension
|
66
|
-
if height < 480 then ' -s hd480'
|
67
|
-
elsif height <= 720 then ' -s hd720'
|
68
|
-
else ' -s hd1080'
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
# @return [String] comando analise
|
73
|
-
def cmd_probe
|
74
|
-
"ffprobe -hide_banner -show_streams \"#{nome}\" 2>&1|grep -v title"
|
75
|
-
end
|
76
|
-
|
77
|
-
# Comando para processar videos
|
78
|
-
#
|
79
|
-
# @param [String] tempo do video processado
|
80
|
-
# @return [String] comando conversao
|
81
|
-
def cmd_mpeg(tempo)
|
82
|
-
puts "processar #{base}.mp4 " + join_opcoes
|
83
|
-
"ffmpeg #{geral} -i \"#{nome}\" -y -an " + join_opcoes +
|
84
|
-
' -metadata title= -metadata artist= -metadata comment= -metadata major_brand= -metadata compatible_brands=' +
|
85
|
-
# para teste produz somente segundos
|
86
|
-
tempo
|
87
|
-
end
|
88
|
-
|
89
|
-
# @return [String] opcoes para trabalho framerate & bitrate & dimenssoes
|
90
|
-
def join_opcoes
|
91
|
-
"-r #{[fps, 25].min} -b:v #{[bitrate, 2000].min}k" + dimension + aspect
|
92
|
-
end
|
93
|
-
|
94
|
-
# @return [String] opcoes gerais comando conversao
|
95
|
-
def geral
|
96
|
-
'-loglevel quiet -hide_banner' +
|
97
|
-
# para ignorar segundos no inicio
|
98
|
-
# ' -ss 15' \
|
99
|
-
''
|
100
|
-
end
|
101
|
-
|
102
|
-
# Processa videos
|
103
|
-
#
|
104
|
-
# @param [Hash] opcoes parametrizacao
|
105
|
-
# @option opcoes [Array<String>] :d locais onde procurar videos
|
106
|
-
# @option opcoes [<String>] :i pasta origem dos videos
|
107
|
-
# @option opcoes [<String>] :o pasta destino dos videos
|
108
|
-
# @option opcoes [<Boolean>] :t processa somente segundos para teste
|
109
|
-
# @param [String] aot pasta destino dos videos absoluta
|
110
|
-
def processa(opcoes, aot)
|
111
|
-
return if ofok?(aot) || vdok?(opcoes[:d], opcoes[:o])
|
112
|
-
|
113
|
-
system cmd_mpeg(opcoes[:t] ? ' -t 20' : '') + " #{aot}/#{base}.mp4"
|
114
|
-
vfok?(HRVideo.new("#{aot}/#{base}.mp4"))
|
115
|
-
end
|
116
|
-
|
117
|
-
# Testa videos
|
118
|
-
#
|
119
|
-
# @param [Hash] opcoes parametrizacao
|
120
|
-
# @option opcoes [Array<String>] :d locais onde procurar videos
|
121
|
-
# @option opcoes [<String>] :i pasta origem dos videos
|
122
|
-
# @option opcoes [<String>] :o pasta destino dos videos
|
123
|
-
# @option opcoes [<Boolean>] :t processa somente segundos para teste
|
124
|
-
# @param [String] aot pasta destino dos videos absoluta
|
125
|
-
def testa(opcoes, aot)
|
126
|
-
return if ofok?(aot) || vdok?(opcoes[:d], opcoes[:o])
|
127
|
-
|
128
|
-
puts "ls -lh \"#{nome}\" # #{show}"
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|