ffprober 0.5.5 → 1.0
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/Changes.md +6 -0
- data/Gemfile +2 -0
- data/README.md +3 -3
- data/ffprober.gemspec +21 -5
- data/lib/ffprober.rb +9 -0
- data/lib/ffprober/audio_stream.rb +1 -0
- data/lib/ffprober/chapter.rb +1 -0
- data/lib/ffprober/data_stream.rb +1 -0
- data/lib/ffprober/dynamic_initializer.rb +4 -0
- data/lib/ffprober/ffmpeg/exec.rb +12 -5
- data/lib/ffprober/ffmpeg/finder.rb +30 -9
- data/lib/ffprober/ffmpeg/version.rb +25 -8
- data/lib/ffprober/ffmpeg/version_validator.rb +8 -1
- data/lib/ffprober/ffprobe_version.rb +9 -0
- data/lib/ffprober/format.rb +1 -0
- data/lib/ffprober/parser.rb +7 -0
- data/lib/ffprober/parsers/file.rb +11 -3
- data/lib/ffprober/parsers/json.rb +2 -0
- data/lib/ffprober/parsers/url.rb +4 -5
- data/lib/ffprober/stream.rb +1 -0
- data/lib/ffprober/subtitle_stream.rb +1 -0
- data/lib/ffprober/version.rb +2 -1
- data/lib/ffprober/video_stream.rb +1 -0
- data/lib/ffprober/wrapper.rb +21 -4
- metadata +83 -26
- data/.codeclimate.yml +0 -4
- data/.github/workflows/gempush.yml +0 -41
- data/.github/workflows/ruby.yml +0 -30
- data/.gitignore +0 -18
- data/.rspec +0 -2
- data/.rubocop.yml +0 -6
- data/.ruby-version +0 -1
- data/.travis.yml +0 -30
- data/Rakefile +0 -12
- data/bin/console +0 -15
- data/bin/setup +0 -7
- data/circle.yml +0 -5
- data/examples/from_file.rb +0 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7d8c232d9ed83bd2d51a9ff879008d26deadc3ddf62970cca4e9e15ad118c01f
|
|
4
|
+
data.tar.gz: b13c5c21ac3942019be942f242d06c3d63d577c9332940dbd1e7e2bb3768f364
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 994061aa59b82948a63d753ca191c7a501e5d474117c67231ddd3131ef0574a51750693c697cafdd45269af7c29817619ef32a3405f5ac6988501ceef2d45b2e
|
|
7
|
+
data.tar.gz: 1209f4ff0162d55cc019d5434d87b0236e6bbb6b13b87a58c0a665e97ebc2701e6a5668e08580348497e36e48210a8efd4897c317f7b376e4cbc849a2c3f9007
|
data/Changes.md
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -27,7 +27,7 @@ Or install it yourself as:
|
|
|
27
27
|
|
|
28
28
|
## FFMPEG version
|
|
29
29
|
|
|
30
|
-
tested with ffprobe version 0.9 upto 3.
|
|
30
|
+
tested with ffprobe version 0.9 upto 4.3.1
|
|
31
31
|
|
|
32
32
|
according to [ffmpeg changelog](http://git.videolan.org/?p=ffmpeg.git;a=blob_plain;f=Changelog) json output was added in version 0.9
|
|
33
33
|
|
|
@@ -43,9 +43,9 @@ help me collecting various version outputs of fprobe/ffmpeg
|
|
|
43
43
|
|
|
44
44
|
## Supported Rubies
|
|
45
45
|
|
|
46
|
-
Ffprober is tested under 2.4, 2.5, 2.6
|
|
46
|
+
Ffprober is tested under 2.4, 2.5, 2.6 and 2.7.
|
|
47
47
|
|
|
48
|
-
[](https://github.com/beanieboi/ffprober/actions?query=workflow%3ARuby)
|
|
49
49
|
|
|
50
50
|
[](https://codeclimate.com/github/beanieboi/ffprober/maintainability)
|
|
51
51
|
|
data/ffprober.gemspec
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
# typed: strong
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
|
-
lib = File.expand_path('
|
|
4
|
+
lib = File.expand_path('lib', __dir__)
|
|
4
5
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
5
6
|
require 'ffprober/version'
|
|
6
7
|
|
|
@@ -15,14 +16,29 @@ Gem::Specification.new do |spec|
|
|
|
15
16
|
spec.homepage = 'https://github.com/beanieboi/ffprober'
|
|
16
17
|
spec.license = 'MIT'
|
|
17
18
|
|
|
18
|
-
spec.files =
|
|
19
|
+
spec.files = Dir[
|
|
20
|
+
'CODE_OF_CONDUCT.md',
|
|
21
|
+
'CONTRIBUTING.md',
|
|
22
|
+
'Changes.md',
|
|
23
|
+
'Gemfile',
|
|
24
|
+
'ffprober.gemspec',
|
|
25
|
+
'lib/**/*',
|
|
26
|
+
'LICENSE',
|
|
27
|
+
'README.md'
|
|
28
|
+
]
|
|
19
29
|
spec.bindir = 'exe'
|
|
20
30
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
21
31
|
spec.require_paths = ['lib']
|
|
22
32
|
|
|
23
|
-
spec.required_ruby_version = '
|
|
33
|
+
spec.required_ruby_version = '>= 2.0'
|
|
34
|
+
|
|
35
|
+
spec.add_runtime_dependency 'sorbet-runtime'
|
|
24
36
|
|
|
25
|
-
spec.add_development_dependency 'rake', '~> 12.3'
|
|
26
37
|
spec.add_development_dependency 'minitest', '~> 5'
|
|
27
|
-
spec.add_development_dependency '
|
|
38
|
+
spec.add_development_dependency 'rake', '~> 12.3'
|
|
39
|
+
spec.add_development_dependency 'rubocop', '~> 1'
|
|
40
|
+
spec.add_development_dependency 'rubocop-minitest'
|
|
41
|
+
spec.add_development_dependency 'rubocop-packaging'
|
|
42
|
+
spec.add_development_dependency 'rubocop-sorbet'
|
|
43
|
+
spec.add_development_dependency 'simplecov', '~> 0.19'
|
|
28
44
|
end
|
data/lib/ffprober.rb
CHANGED
|
@@ -1,14 +1,23 @@
|
|
|
1
|
+
# typed: true
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
4
|
+
require 'bundler'
|
|
5
|
+
Bundler.setup
|
|
6
|
+
|
|
7
|
+
require 'sorbet-runtime'
|
|
3
8
|
require_relative 'ffprober/version'
|
|
4
9
|
|
|
5
10
|
autoload :JSON, 'json'
|
|
6
11
|
|
|
7
12
|
module Ffprober
|
|
8
13
|
class EmptyInput < StandardError; end
|
|
14
|
+
|
|
9
15
|
class InvalidInputFileError < StandardError; end
|
|
16
|
+
|
|
10
17
|
class NoFfprobeFound < StandardError; end
|
|
18
|
+
|
|
11
19
|
class UnsupportedVersion < StandardError; end
|
|
20
|
+
|
|
12
21
|
class FfprobeError < StandardError
|
|
13
22
|
def initialize(ff_err)
|
|
14
23
|
super("Ffprobe responded with: #{ff_err[:string]} (#{ff_err[:code]})")
|
data/lib/ffprober/chapter.rb
CHANGED
data/lib/ffprober/data_stream.rb
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
|
+
# typed: true
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module Ffprober
|
|
4
5
|
module DynamicInitializer
|
|
6
|
+
include Kernel
|
|
7
|
+
|
|
5
8
|
def initialize(object_attribute_hash)
|
|
6
9
|
object_attribute_hash.each do |key, value|
|
|
7
10
|
instance_variable_set("@#{key}", value)
|
|
8
11
|
|
|
9
12
|
next if self.class.method_defined?(key)
|
|
13
|
+
|
|
10
14
|
self.class.send(:define_method, key) do
|
|
11
15
|
instance_variable_get("@#{key}")
|
|
12
16
|
end
|
data/lib/ffprober/ffmpeg/exec.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# typed: strict
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
require 'shellwords'
|
|
@@ -5,16 +6,22 @@ require 'shellwords'
|
|
|
5
6
|
module Ffprober
|
|
6
7
|
module Ffmpeg
|
|
7
8
|
class Exec
|
|
8
|
-
|
|
9
|
+
extend T::Sig
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
CHAPTER_SUPPORT = T.let(Gem::Version.new('2.0.0'), Gem::Version)
|
|
12
|
+
|
|
13
|
+
sig { params(finder: T.any(Ffprober::Ffmpeg::Finder, T.untyped)).void }
|
|
14
|
+
def initialize(finder = Ffprober::Ffmpeg::Finder.new)
|
|
11
15
|
@finder = finder
|
|
16
|
+
@ffprobe_version_output = T.let(nil, T.nilable(String))
|
|
12
17
|
end
|
|
13
18
|
|
|
19
|
+
sig { params(filename: String).returns(String) }
|
|
14
20
|
def json_output(filename)
|
|
15
21
|
`#{@finder.path} #{ffprobe_options} #{Shellwords.escape(filename)}`
|
|
16
22
|
end
|
|
17
23
|
|
|
24
|
+
sig { returns(String) }
|
|
18
25
|
def ffprobe_version_output
|
|
19
26
|
@ffprobe_version_output ||= begin
|
|
20
27
|
if @finder.path.nil?
|
|
@@ -25,17 +32,17 @@ module Ffprober
|
|
|
25
32
|
end
|
|
26
33
|
end
|
|
27
34
|
|
|
35
|
+
sig { returns(String) }
|
|
28
36
|
def ffprobe_options
|
|
29
37
|
base_options = '-v quiet -print_format json -show_format'\
|
|
30
38
|
' -show_streams -show_error'
|
|
31
39
|
|
|
32
|
-
if ffprobe_version.version >= CHAPTER_SUPPORT
|
|
33
|
-
options = base_options + ' -show_chapters'
|
|
34
|
-
end
|
|
40
|
+
options = "#{base_options} -show_chapters" if ffprobe_version.version >= CHAPTER_SUPPORT
|
|
35
41
|
|
|
36
42
|
options || base_options
|
|
37
43
|
end
|
|
38
44
|
|
|
45
|
+
sig { returns(Ffprober::Ffmpeg::Version) }
|
|
39
46
|
def ffprobe_version
|
|
40
47
|
Ffprober::Ffmpeg::Version.new(self)
|
|
41
48
|
end
|
|
@@ -1,26 +1,47 @@
|
|
|
1
|
+
# typed: strong
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module Ffprober
|
|
4
5
|
module Ffmpeg
|
|
5
6
|
class Finder
|
|
6
|
-
|
|
7
|
+
extend T::Sig
|
|
8
|
+
SEARCH_PATHS = T.let(ENV['PATH'], T.nilable(String))
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
sig { returns(String) }
|
|
11
|
+
attr_reader :executable_name
|
|
12
|
+
|
|
13
|
+
sig { void }
|
|
14
|
+
def initialize
|
|
15
|
+
@executable_path = T.let(nil, T.nilable(String))
|
|
16
|
+
@executable_name = T.let(executable_name_picker, String)
|
|
17
|
+
@path = T.let(nil, T.nilable(String))
|
|
11
18
|
end
|
|
12
19
|
|
|
13
|
-
|
|
14
|
-
|
|
20
|
+
sig { returns(String) }
|
|
21
|
+
def path
|
|
22
|
+
raise Ffprober::NoFfprobeFound, 'ffprobe executable not found' if executable_path.nil?
|
|
23
|
+
|
|
24
|
+
@path ||= File.expand_path(executable_name, executable_path)
|
|
15
25
|
end
|
|
16
26
|
|
|
17
|
-
|
|
27
|
+
sig { returns(T::Boolean) }
|
|
28
|
+
def windows?
|
|
18
29
|
!(RUBY_PLATFORM =~ /(mingw|mswin)/).nil?
|
|
19
30
|
end
|
|
20
31
|
|
|
21
|
-
|
|
32
|
+
sig { returns(String) }
|
|
33
|
+
def executable_name_picker
|
|
34
|
+
if windows?
|
|
35
|
+
T.let('ffprobe.exe', String)
|
|
36
|
+
else
|
|
37
|
+
T.let('ffprobe', String)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
sig { returns(T.nilable(String)) }
|
|
42
|
+
def executable_path
|
|
22
43
|
@executable_path ||= begin
|
|
23
|
-
SEARCH_PATHS.split(File::PATH_SEPARATOR).detect do |path_to_check|
|
|
44
|
+
T.must(SEARCH_PATHS).split(File::PATH_SEPARATOR).detect do |path_to_check|
|
|
24
45
|
File.executable?(File.join(path_to_check, executable_name))
|
|
25
46
|
end
|
|
26
47
|
end
|
|
@@ -1,38 +1,55 @@
|
|
|
1
|
+
# typed: strict
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module Ffprober
|
|
4
5
|
module Ffmpeg
|
|
5
6
|
class Version
|
|
7
|
+
extend T::Sig
|
|
8
|
+
|
|
9
|
+
sig { params(ffprobe_exec: T.any(Ffprober::Ffmpeg::Exec, T.untyped)).void }
|
|
6
10
|
def initialize(ffprobe_exec = Ffprober::Ffmpeg::Exec.new)
|
|
7
11
|
@ffprobe_exec = ffprobe_exec
|
|
12
|
+
@version = T.let(nil, T.nilable(Gem::Version))
|
|
13
|
+
@parse_version = T.let(nil, T.nilable(T::Array[Integer]))
|
|
8
14
|
end
|
|
9
15
|
|
|
10
|
-
VERSION_REGEX = /^(ffprobe|avprobe|ffmpeg) version (\d+)\.?(\d+)\.?(\d+)
|
|
11
|
-
NIGHTLY_REGEX = /^(ffprobe|avprobe|ffmpeg) version (N|git)
|
|
12
|
-
VERSION_FALLBACK = [0, 0, 0].freeze
|
|
16
|
+
VERSION_REGEX = T.let(/^(ffprobe|avprobe|ffmpeg) version (\d+)\.?(\d+)\.?(\d+)*/.freeze, Regexp)
|
|
17
|
+
NIGHTLY_REGEX = T.let(/^(ffprobe|avprobe|ffmpeg) version (N|git)-/.freeze, Regexp)
|
|
18
|
+
VERSION_FALLBACK = T.let([0, 0, 0].freeze, T::Array[Integer])
|
|
13
19
|
|
|
20
|
+
sig { returns(Gem::Version) }
|
|
14
21
|
def version
|
|
15
22
|
@version ||= Gem::Version.new(parse_version.join('.'))
|
|
16
23
|
end
|
|
17
24
|
|
|
25
|
+
sig { returns(T::Boolean) }
|
|
18
26
|
def nightly?
|
|
19
27
|
!(ffprobe_version_output =~ NIGHTLY_REGEX).nil?
|
|
20
28
|
end
|
|
21
29
|
|
|
22
30
|
private
|
|
23
31
|
|
|
32
|
+
sig { returns(T::Array[Integer]) }
|
|
24
33
|
def parse_version
|
|
25
|
-
@parse_version
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
34
|
+
return @parse_version if @parse_version
|
|
35
|
+
|
|
36
|
+
match_data = ffprobe_version_output.match(VERSION_REGEX)
|
|
37
|
+
|
|
38
|
+
@parse_version = if match_data
|
|
39
|
+
[match_data[2].to_i, match_data[3].to_i, match_data[4].to_i]
|
|
40
|
+
else
|
|
41
|
+
VERSION_FALLBACK
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
@parse_version
|
|
30
45
|
end
|
|
31
46
|
|
|
47
|
+
sig { returns(String) }
|
|
32
48
|
def ffprobe_version_output
|
|
33
49
|
@ffprobe_exec.ffprobe_version_output
|
|
34
50
|
end
|
|
35
51
|
|
|
52
|
+
sig { returns(String) }
|
|
36
53
|
def to_s
|
|
37
54
|
parse_version.join('.')
|
|
38
55
|
end
|
|
@@ -1,24 +1,31 @@
|
|
|
1
|
+
# typed: strict
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module Ffprober
|
|
4
5
|
module Ffmpeg
|
|
5
6
|
class VersionValidator
|
|
6
|
-
|
|
7
|
+
extend T::Sig
|
|
7
8
|
|
|
9
|
+
MIN_VERSION = T.let(Gem::Version.new('0.9.0'), Gem::Version)
|
|
10
|
+
|
|
11
|
+
sig { params(ffmpeg_version: Ffprober::Ffmpeg::Version).void }
|
|
8
12
|
def initialize(ffmpeg_version)
|
|
9
13
|
@ffmpeg_version = ffmpeg_version
|
|
10
14
|
end
|
|
11
15
|
|
|
16
|
+
sig { returns(T::Boolean) }
|
|
12
17
|
def valid?
|
|
13
18
|
ffmpeg_version.nightly? || version_requirement_statisfied?
|
|
14
19
|
end
|
|
15
20
|
|
|
16
21
|
private
|
|
17
22
|
|
|
23
|
+
sig { returns(T::Boolean) }
|
|
18
24
|
def version_requirement_statisfied?
|
|
19
25
|
MIN_VERSION <= ffmpeg_version.version
|
|
20
26
|
end
|
|
21
27
|
|
|
28
|
+
sig { returns(Ffprober::Ffmpeg::Version) }
|
|
22
29
|
attr_reader :ffmpeg_version
|
|
23
30
|
end
|
|
24
31
|
end
|
|
@@ -1,31 +1,40 @@
|
|
|
1
|
+
# typed: strict
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module Ffprober
|
|
4
5
|
class FfprobeVersion
|
|
6
|
+
extend T::Sig
|
|
7
|
+
|
|
8
|
+
sig { returns(T::Boolean) }
|
|
5
9
|
def self.invalid?
|
|
6
10
|
!new.valid?
|
|
7
11
|
end
|
|
8
12
|
|
|
13
|
+
sig { returns(T::Boolean) }
|
|
9
14
|
def self.valid?
|
|
10
15
|
new.valid?
|
|
11
16
|
rescue NoFfprobeFound
|
|
12
17
|
false
|
|
13
18
|
end
|
|
14
19
|
|
|
20
|
+
sig { returns(T::Boolean) }
|
|
15
21
|
def valid?
|
|
16
22
|
validator.valid?
|
|
17
23
|
end
|
|
18
24
|
|
|
25
|
+
sig { returns(Ffprober::Ffmpeg::Version) }
|
|
19
26
|
def self.version
|
|
20
27
|
new.version
|
|
21
28
|
end
|
|
22
29
|
|
|
30
|
+
sig { returns(Ffprober::Ffmpeg::Version) }
|
|
23
31
|
def version
|
|
24
32
|
Ffprober::Ffmpeg::Version.new
|
|
25
33
|
end
|
|
26
34
|
|
|
27
35
|
private
|
|
28
36
|
|
|
37
|
+
sig { returns(Ffprober::Ffmpeg::VersionValidator) }
|
|
29
38
|
def validator
|
|
30
39
|
Ffprober::Ffmpeg::VersionValidator.new(version)
|
|
31
40
|
end
|
data/lib/ffprober/format.rb
CHANGED
data/lib/ffprober/parser.rb
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
# typed: strict
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module Ffprober
|
|
4
5
|
class Parser
|
|
6
|
+
extend T::Sig
|
|
7
|
+
|
|
8
|
+
sig { params(file_to_parse: String).returns(Ffprober::Wrapper) }
|
|
5
9
|
def self.from_file(file_to_parse)
|
|
6
10
|
check_version
|
|
7
11
|
|
|
@@ -12,6 +16,7 @@ module Ffprober
|
|
|
12
16
|
Ffprober::Wrapper.new(json_parser.json)
|
|
13
17
|
end
|
|
14
18
|
|
|
19
|
+
sig { params(url_to_parse: T.untyped).returns(Ffprober::Wrapper) }
|
|
15
20
|
def self.from_url(url_to_parse)
|
|
16
21
|
check_version
|
|
17
22
|
|
|
@@ -20,11 +25,13 @@ module Ffprober
|
|
|
20
25
|
Ffprober::Wrapper.new(json_parser.json)
|
|
21
26
|
end
|
|
22
27
|
|
|
28
|
+
sig { params(json_to_parse: T.untyped).returns(Ffprober::Wrapper) }
|
|
23
29
|
def self.from_json(json_to_parse)
|
|
24
30
|
json_parser = Parsers::JsonParser.new(json_to_parse)
|
|
25
31
|
Ffprober::Wrapper.new(json_parser.json)
|
|
26
32
|
end
|
|
27
33
|
|
|
34
|
+
sig { returns(NilClass) }
|
|
28
35
|
def self.check_version
|
|
29
36
|
msg = "found version: #{FfprobeVersion.version}"
|
|
30
37
|
raise UnsupportedVersion, msg if FfprobeVersion.invalid?
|
|
@@ -1,17 +1,25 @@
|
|
|
1
|
+
# typed: strict
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module Ffprober
|
|
4
5
|
module Parsers
|
|
5
6
|
class FileParser
|
|
7
|
+
extend T::Sig
|
|
8
|
+
|
|
9
|
+
sig do
|
|
10
|
+
params(
|
|
11
|
+
file_to_parse: String,
|
|
12
|
+
exec: T.any(Ffprober::Ffmpeg::Exec, T.untyped)
|
|
13
|
+
).void
|
|
14
|
+
end
|
|
6
15
|
def initialize(file_to_parse, exec = Ffprober::Ffmpeg::Exec.new)
|
|
7
|
-
unless ::File.exist?(file_to_parse)
|
|
8
|
-
raise ArgumentError, "File not found #{file_to_parse}"
|
|
9
|
-
end
|
|
16
|
+
raise ArgumentError, "File not found #{file_to_parse}" unless ::File.exist?(file_to_parse)
|
|
10
17
|
|
|
11
18
|
@file_to_parse = file_to_parse
|
|
12
19
|
@exec = exec
|
|
13
20
|
end
|
|
14
21
|
|
|
22
|
+
sig { returns(Ffprober::Parsers::JsonParser) }
|
|
15
23
|
def load
|
|
16
24
|
JsonParser.new(@exec.json_output(@file_to_parse))
|
|
17
25
|
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# typed: true
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module Ffprober
|
|
@@ -5,6 +6,7 @@ module Ffprober
|
|
|
5
6
|
class JsonParser
|
|
6
7
|
def initialize(json_to_parse)
|
|
7
8
|
raise ArgumentError, 'No JSON input data' if json_to_parse.nil?
|
|
9
|
+
|
|
8
10
|
@json_to_parse = json_to_parse
|
|
9
11
|
end
|
|
10
12
|
|
data/lib/ffprober/parsers/url.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# typed: true
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
require 'uri'
|
|
@@ -5,12 +6,10 @@ require 'uri'
|
|
|
5
6
|
module Ffprober
|
|
6
7
|
module Parsers
|
|
7
8
|
class UrlParser
|
|
8
|
-
VALID_URI_REGEX = /\A#{URI::DEFAULT_PARSER.make_regexp}\z
|
|
9
|
+
VALID_URI_REGEX = /\A#{URI::DEFAULT_PARSER.make_regexp}\z/.freeze
|
|
9
10
|
|
|
10
11
|
def initialize(url_to_parse, exec = Ffprober::Ffmpeg::Exec.new)
|
|
11
|
-
unless valid_url?(url_to_parse)
|
|
12
|
-
raise ArgumentError, "#{url_to_parse} is not a valid URL"
|
|
13
|
-
end
|
|
12
|
+
raise ArgumentError, "#{url_to_parse} is not a valid URL" unless valid_url?(url_to_parse)
|
|
14
13
|
|
|
15
14
|
@url_to_parse = url_to_parse
|
|
16
15
|
@exec = exec
|
|
@@ -23,7 +22,7 @@ module Ffprober
|
|
|
23
22
|
private
|
|
24
23
|
|
|
25
24
|
def valid_url?(url)
|
|
26
|
-
|
|
25
|
+
url.gsub(' ', '%20') =~ VALID_URI_REGEX
|
|
27
26
|
end
|
|
28
27
|
end
|
|
29
28
|
end
|
data/lib/ffprober/stream.rb
CHANGED
data/lib/ffprober/version.rb
CHANGED
data/lib/ffprober/wrapper.rb
CHANGED
|
@@ -1,40 +1,57 @@
|
|
|
1
|
+
# typed: true
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module Ffprober
|
|
4
5
|
class Wrapper
|
|
6
|
+
extend T::Sig
|
|
7
|
+
|
|
5
8
|
attr_reader :json
|
|
6
9
|
|
|
10
|
+
sig { returns(Ffprober::Format) }
|
|
11
|
+
attr_reader :format
|
|
12
|
+
|
|
13
|
+
# rubocop:disable Metrics/AbcSize
|
|
14
|
+
sig { params(json: T::Hash[T.untyped, T.untyped]).void }
|
|
7
15
|
def initialize(json)
|
|
8
16
|
raise FfprobeError, json[:error] if json[:error]
|
|
9
|
-
@json = json
|
|
10
|
-
end
|
|
11
17
|
|
|
12
|
-
|
|
13
|
-
@format
|
|
18
|
+
@json = json
|
|
19
|
+
@format = T.let(Format.new(json[:format]), Ffprober::Format)
|
|
20
|
+
@video_streams = T.let(nil, T.nilable(T::Array[Ffprober::VideoStream]))
|
|
21
|
+
@audio_streams = T.let(nil, T.nilable(T::Array[Ffprober::AudioStream]))
|
|
22
|
+
@data_streams = T.let(nil, T.nilable(T::Array[Ffprober::DataStream]))
|
|
23
|
+
@subtitle_streams = T.let(nil, T.nilable(T::Array[Ffprober::SubtitleStream]))
|
|
24
|
+
@chapters = T.let(nil, T.nilable(T::Array[Ffprober::Chapter]))
|
|
14
25
|
end
|
|
26
|
+
# rubocop:enable Metrics/AbcSize
|
|
15
27
|
|
|
28
|
+
sig { returns(T::Array[Ffprober::VideoStream]) }
|
|
16
29
|
def video_streams
|
|
17
30
|
@video_streams ||= stream_by_codec('video').map do |data|
|
|
18
31
|
VideoStream.new(data)
|
|
19
32
|
end
|
|
20
33
|
end
|
|
21
34
|
|
|
35
|
+
sig { returns(T::Array[Ffprober::AudioStream]) }
|
|
22
36
|
def audio_streams
|
|
23
37
|
@audio_streams ||= stream_by_codec('audio').map do |data|
|
|
24
38
|
AudioStream.new(data)
|
|
25
39
|
end
|
|
26
40
|
end
|
|
27
41
|
|
|
42
|
+
sig { returns(T::Array[Ffprober::DataStream]) }
|
|
28
43
|
def data_streams
|
|
29
44
|
@data_streams ||= stream_by_codec('data').map do |data|
|
|
30
45
|
DataStream.new(data)
|
|
31
46
|
end
|
|
32
47
|
end
|
|
33
48
|
|
|
49
|
+
sig { returns(T::Array[Ffprober::Chapter]) }
|
|
34
50
|
def chapters
|
|
35
51
|
@chapters ||= json[:chapters].map { |chapter| Chapter.new(chapter) }
|
|
36
52
|
end
|
|
37
53
|
|
|
54
|
+
sig { returns(T::Array[Ffprober::SubtitleStream]) }
|
|
38
55
|
def subtitle_streams
|
|
39
56
|
@subtitle_streams ||= stream_by_codec('subtitle').map do |stream|
|
|
40
57
|
SubtitleStream.new(stream)
|
metadata
CHANGED
|
@@ -1,15 +1,43 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ffprober
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0
|
|
4
|
+
version: '1.0'
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- beanieboi
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2020-
|
|
11
|
+
date: 2020-11-28 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: sorbet-runtime
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: minitest
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '5'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '5'
|
|
13
41
|
- !ruby/object:Gem::Dependency
|
|
14
42
|
name: rake
|
|
15
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -25,33 +53,75 @@ dependencies:
|
|
|
25
53
|
- !ruby/object:Gem::Version
|
|
26
54
|
version: '12.3'
|
|
27
55
|
- !ruby/object:Gem::Dependency
|
|
28
|
-
name:
|
|
56
|
+
name: rubocop
|
|
29
57
|
requirement: !ruby/object:Gem::Requirement
|
|
30
58
|
requirements:
|
|
31
59
|
- - "~>"
|
|
32
60
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '
|
|
61
|
+
version: '1'
|
|
34
62
|
type: :development
|
|
35
63
|
prerelease: false
|
|
36
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
65
|
requirements:
|
|
38
66
|
- - "~>"
|
|
39
67
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '
|
|
68
|
+
version: '1'
|
|
41
69
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name: rubocop
|
|
70
|
+
name: rubocop-minitest
|
|
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'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: rubocop-packaging
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '0'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: rubocop-sorbet
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - ">="
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '0'
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - ">="
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '0'
|
|
111
|
+
- !ruby/object:Gem::Dependency
|
|
112
|
+
name: simplecov
|
|
43
113
|
requirement: !ruby/object:Gem::Requirement
|
|
44
114
|
requirements:
|
|
45
115
|
- - "~>"
|
|
46
116
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '0.
|
|
117
|
+
version: '0.19'
|
|
48
118
|
type: :development
|
|
49
119
|
prerelease: false
|
|
50
120
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
121
|
requirements:
|
|
52
122
|
- - "~>"
|
|
53
123
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: '0.
|
|
124
|
+
version: '0.19'
|
|
55
125
|
description: a Ruby wrapper for ffprobe
|
|
56
126
|
email:
|
|
57
127
|
- beanie@benle.de
|
|
@@ -59,25 +129,12 @@ executables: []
|
|
|
59
129
|
extensions: []
|
|
60
130
|
extra_rdoc_files: []
|
|
61
131
|
files:
|
|
62
|
-
- ".codeclimate.yml"
|
|
63
|
-
- ".github/workflows/gempush.yml"
|
|
64
|
-
- ".github/workflows/ruby.yml"
|
|
65
|
-
- ".gitignore"
|
|
66
|
-
- ".rspec"
|
|
67
|
-
- ".rubocop.yml"
|
|
68
|
-
- ".ruby-version"
|
|
69
|
-
- ".travis.yml"
|
|
70
132
|
- CODE_OF_CONDUCT.md
|
|
71
133
|
- CONTRIBUTING.md
|
|
72
134
|
- Changes.md
|
|
73
135
|
- Gemfile
|
|
74
136
|
- LICENSE
|
|
75
137
|
- README.md
|
|
76
|
-
- Rakefile
|
|
77
|
-
- bin/console
|
|
78
|
-
- bin/setup
|
|
79
|
-
- circle.yml
|
|
80
|
-
- examples/from_file.rb
|
|
81
138
|
- ffprober.gemspec
|
|
82
139
|
- lib/ffprober.rb
|
|
83
140
|
- lib/ffprober/audio_stream.rb
|
|
@@ -103,13 +160,13 @@ homepage: https://github.com/beanieboi/ffprober
|
|
|
103
160
|
licenses:
|
|
104
161
|
- MIT
|
|
105
162
|
metadata: {}
|
|
106
|
-
post_install_message:
|
|
163
|
+
post_install_message:
|
|
107
164
|
rdoc_options: []
|
|
108
165
|
require_paths:
|
|
109
166
|
- lib
|
|
110
167
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
111
168
|
requirements:
|
|
112
|
-
- - "
|
|
169
|
+
- - ">="
|
|
113
170
|
- !ruby/object:Gem::Version
|
|
114
171
|
version: '2.0'
|
|
115
172
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
@@ -118,8 +175,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
118
175
|
- !ruby/object:Gem::Version
|
|
119
176
|
version: '0'
|
|
120
177
|
requirements: []
|
|
121
|
-
rubygems_version: 3.1.
|
|
122
|
-
signing_key:
|
|
178
|
+
rubygems_version: 3.1.4
|
|
179
|
+
signing_key:
|
|
123
180
|
specification_version: 4
|
|
124
181
|
summary: a Ruby wrapper for ffprobe (part of ffmpeg)
|
|
125
182
|
test_files: []
|
data/.codeclimate.yml
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
name: Ruby Gem
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
tags:
|
|
6
|
-
- '*'
|
|
7
|
-
|
|
8
|
-
jobs:
|
|
9
|
-
build:
|
|
10
|
-
name: Build + Publish
|
|
11
|
-
runs-on: ubuntu-latest
|
|
12
|
-
|
|
13
|
-
steps:
|
|
14
|
-
- uses: actions/checkout@v2
|
|
15
|
-
- name: Set up Ruby 2.6
|
|
16
|
-
uses: actions/setup-ruby@v1
|
|
17
|
-
with:
|
|
18
|
-
version: 2.6.x
|
|
19
|
-
|
|
20
|
-
- name: Publish to GPR
|
|
21
|
-
run: |
|
|
22
|
-
mkdir -p $HOME/.gem
|
|
23
|
-
touch $HOME/.gem/credentials
|
|
24
|
-
chmod 0600 $HOME/.gem/credentials
|
|
25
|
-
printf -- "---\n:github: Bearer ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
|
26
|
-
gem build *.gemspec
|
|
27
|
-
gem push --KEY github --host https://rubygems.pkg.github.com/${OWNER} *.gem
|
|
28
|
-
env:
|
|
29
|
-
GEM_HOST_API_KEY: ${{secrets.GPR_AUTH_TOKEN}}
|
|
30
|
-
OWNER: beanieboi
|
|
31
|
-
|
|
32
|
-
- name: Publish to RubyGems
|
|
33
|
-
run: |
|
|
34
|
-
mkdir -p $HOME/.gem
|
|
35
|
-
touch $HOME/.gem/credentials
|
|
36
|
-
chmod 0600 $HOME/.gem/credentials
|
|
37
|
-
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
|
38
|
-
gem build *.gemspec
|
|
39
|
-
gem push *.gem
|
|
40
|
-
env:
|
|
41
|
-
GEM_HOST_API_KEY: ${{secrets.RUBYGEMS_AUTH_TOKEN}}
|
data/.github/workflows/ruby.yml
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
name: Ruby
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [ master ]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: [ master ]
|
|
8
|
-
|
|
9
|
-
jobs:
|
|
10
|
-
build:
|
|
11
|
-
|
|
12
|
-
runs-on: ubuntu-latest
|
|
13
|
-
|
|
14
|
-
strategy:
|
|
15
|
-
matrix:
|
|
16
|
-
ruby-version: [2.4, 2.5, 2.6, 2.7]
|
|
17
|
-
|
|
18
|
-
steps:
|
|
19
|
-
- uses: actions/checkout@v2
|
|
20
|
-
- name: Set up Ruby ${{ matrix.ruby-version }}
|
|
21
|
-
uses: actions/setup-ruby@v1
|
|
22
|
-
with:
|
|
23
|
-
ruby-version: ${{ matrix.ruby-version }}
|
|
24
|
-
- name: Build and test with Rake
|
|
25
|
-
run: |
|
|
26
|
-
gem install bundler
|
|
27
|
-
bundle install --jobs 4 --retry 3
|
|
28
|
-
bundle exec rake
|
|
29
|
-
env:
|
|
30
|
-
CI: true
|
data/.gitignore
DELETED
data/.rspec
DELETED
data/.rubocop.yml
DELETED
data/.ruby-version
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
2.7.0
|
data/.travis.yml
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
language: ruby
|
|
2
|
-
|
|
3
|
-
before_install:
|
|
4
|
-
- gem update --system
|
|
5
|
-
- gem install bundler
|
|
6
|
-
|
|
7
|
-
before_script:
|
|
8
|
-
- echo $PATH
|
|
9
|
-
- cp test/ffprobe /home/travis/bin
|
|
10
|
-
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
|
11
|
-
- chmod +x ./cc-test-reporter
|
|
12
|
-
- ./cc-test-reporter before-build
|
|
13
|
-
|
|
14
|
-
after_script:
|
|
15
|
-
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
|
16
|
-
|
|
17
|
-
script: rake
|
|
18
|
-
|
|
19
|
-
sudo: false
|
|
20
|
-
|
|
21
|
-
env:
|
|
22
|
-
global:
|
|
23
|
-
- CC_TEST_REPORTER_ID=e319ec7d18fb8e1f05b460c3ef8fac58af3844d7bfa3d44de6b82eb874bb3e31
|
|
24
|
-
|
|
25
|
-
rvm:
|
|
26
|
-
- 2.4.6
|
|
27
|
-
- 2.5.5
|
|
28
|
-
- 2.6.3
|
|
29
|
-
- ruby-head
|
|
30
|
-
- jruby-head
|
data/Rakefile
DELETED
data/bin/console
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
require 'bundler/setup'
|
|
5
|
-
require 'ffprober'
|
|
6
|
-
|
|
7
|
-
# You can add fixtures and/or initialization code here to make experimenting
|
|
8
|
-
# with your gem easier. You can also use a different console, if you like.
|
|
9
|
-
|
|
10
|
-
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
11
|
-
# require "pry"
|
|
12
|
-
# Pry.start
|
|
13
|
-
|
|
14
|
-
require 'irb'
|
|
15
|
-
IRB.start
|
data/bin/setup
DELETED
data/circle.yml
DELETED