ffprober 0.4.6 → 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,37 +1,57 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
1
4
  module Ffprober
2
5
  module Ffmpeg
3
6
  class Version
4
- VERSION_REGEX = /^(ffprobe|avprobe|ffmpeg) version (\d+)\.?(\d+)\.?(\d+)*/
5
- NIGHTLY_REGEX = /^(ffprobe|avprobe|ffmpeg) version (N|git)-/
7
+ extend T::Sig
8
+
9
+ sig { params(ffprobe_exec: T.any(Ffprober::Ffmpeg::Exec, T.untyped)).void }
10
+ def initialize(ffprobe_exec = Ffprober::Ffmpeg::Exec.new)
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]))
14
+ end
6
15
 
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])
19
+
20
+ sig { returns(Gem::Version) }
7
21
  def version
8
- @version ||= Gem::Version.new(parse_version.join("."))
22
+ @version ||= Gem::Version.new(parse_version.join('.'))
9
23
  end
10
24
 
25
+ sig { returns(T::Boolean) }
11
26
  def nightly?
12
- !!(ffprobe_version_output =~ NIGHTLY_REGEX)
27
+ !(ffprobe_version_output =~ NIGHTLY_REGEX).nil?
13
28
  end
14
29
 
15
30
  private
16
31
 
32
+ sig { returns(T::Array[Integer]) }
17
33
  def parse_version
18
- @parse_version ||= begin
19
- ffprobe_version_output.match(VERSION_REGEX) do |match|
20
- [match[2].to_i, match[3].to_i, match[4].to_i]
21
- end || [0, 0, 0]
22
- end
23
- end
34
+ return @parse_version if @parse_version
24
35
 
25
- def ffprobe_version_output
26
- @ffprobe_version_output ||= ffprobe_finder.path.nil? ? "" : `#{ffprobe_finder.path} -version`
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
27
45
  end
28
46
 
29
- def ffprobe_finder
30
- Ffprober::Ffmpeg::Finder
47
+ sig { returns(String) }
48
+ def ffprobe_version_output
49
+ @ffprobe_exec.ffprobe_version_output
31
50
  end
32
51
 
52
+ sig { returns(String) }
33
53
  def to_s
34
- parse_version.join(".")
54
+ parse_version.join('.')
35
55
  end
36
56
  end
37
57
  end
@@ -1,27 +1,32 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
1
4
  module Ffprober
2
5
  module Ffmpeg
3
6
  class VersionValidator
4
- MIN_VERSION = Gem::Version.new("0.9.0")
5
- MAX_VERSION = Gem::Version.new("2.8.1")
7
+ extend T::Sig
8
+
9
+ MIN_VERSION = T.let(Gem::Version.new('0.9.0'), Gem::Version)
6
10
 
11
+ sig { params(ffmpeg_version: Ffprober::Ffmpeg::Version).void }
7
12
  def initialize(ffmpeg_version)
8
13
  @ffmpeg_version = ffmpeg_version
9
14
  end
10
15
 
16
+ sig { returns(T::Boolean) }
11
17
  def valid?
12
18
  ffmpeg_version.nightly? || version_requirement_statisfied?
13
19
  end
14
20
 
15
21
  private
16
22
 
23
+ sig { returns(T::Boolean) }
17
24
  def version_requirement_statisfied?
18
- version = ffmpeg_version.version
19
- (MIN_VERSION <= version && version <= MAX_VERSION)
25
+ MIN_VERSION <= ffmpeg_version.version
20
26
  end
21
27
 
22
- def ffmpeg_version
23
- @ffmpeg_version
24
- end
28
+ sig { returns(Ffprober::Ffmpeg::Version) }
29
+ attr_reader :ffmpeg_version
25
30
  end
26
31
  end
27
32
  end
@@ -1,21 +1,42 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
1
4
  module Ffprober
2
5
  class FfprobeVersion
6
+ extend T::Sig
7
+
8
+ sig { returns(T::Boolean) }
9
+ def self.invalid?
10
+ !new.valid?
11
+ end
12
+
13
+ sig { returns(T::Boolean) }
3
14
  def self.valid?
4
15
  new.valid?
16
+ rescue NoFfprobeFound
17
+ false
5
18
  end
6
19
 
20
+ sig { returns(T::Boolean) }
7
21
  def valid?
8
22
  validator.valid?
9
23
  end
10
24
 
11
- private
12
-
13
- def validator
14
- Ffprober::Ffmpeg::VersionValidator.new(version)
25
+ sig { returns(Ffprober::Ffmpeg::Version) }
26
+ def self.version
27
+ new.version
15
28
  end
16
29
 
30
+ sig { returns(Ffprober::Ffmpeg::Version) }
17
31
  def version
18
32
  Ffprober::Ffmpeg::Version.new
19
33
  end
34
+
35
+ private
36
+
37
+ sig { returns(Ffprober::Ffmpeg::VersionValidator) }
38
+ def validator
39
+ Ffprober::Ffmpeg::VersionValidator.new(version)
40
+ end
20
41
  end
21
42
  end
@@ -1,3 +1,6 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
1
4
  module Ffprober
2
5
  class Format
3
6
  include Ffprober::DynamicInitializer
@@ -1,20 +1,40 @@
1
- require "shellwords"
1
+ # typed: strict
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
- unless FfprobeVersion.valid?
7
- fail ArgumentError.new("no or unsupported ffprobe version found. (version: #{Ffprober::Ffmpeg::Version.new})")
8
- end
10
+ check_version
11
+
12
+ raise EmptyInput, file_to_parse if File.zero?(file_to_parse)
9
13
 
10
- file_parser = Ffprober::Parsers::File.new(file_to_parse)
14
+ file_parser = Parsers::FileParser.new(file_to_parse)
11
15
  json_parser = file_parser.load
12
16
  Ffprober::Wrapper.new(json_parser.json)
13
17
  end
14
18
 
19
+ sig { params(url_to_parse: T.untyped).returns(Ffprober::Wrapper) }
20
+ def self.from_url(url_to_parse)
21
+ check_version
22
+
23
+ url_parser = Parsers::UrlParser.new(url_to_parse)
24
+ json_parser = url_parser.load
25
+ Ffprober::Wrapper.new(json_parser.json)
26
+ end
27
+
28
+ sig { params(json_to_parse: T.untyped).returns(Ffprober::Wrapper) }
15
29
  def self.from_json(json_to_parse)
16
- json_parser = Ffprober::Parsers::Json.new(json_to_parse)
30
+ json_parser = Parsers::JsonParser.new(json_to_parse)
17
31
  Ffprober::Wrapper.new(json_parser.json)
18
32
  end
33
+
34
+ sig { returns(NilClass) }
35
+ def self.check_version
36
+ msg = "found version: #{FfprobeVersion.version}"
37
+ raise UnsupportedVersion, msg if FfprobeVersion.invalid?
38
+ end
19
39
  end
20
40
  end
@@ -1,33 +1,27 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
1
4
  module Ffprober
2
5
  module Parsers
3
- class File
4
- def initialize(file_to_parse)
5
- unless ::File.exist?(file_to_parse)
6
- fail ArgumentError.new("File not found #{file_to_parse}")
7
- end
8
-
9
- @file_to_parse = file_to_parse
10
- end
11
-
12
- def load
13
- json_output = `#{ffprobe_finder.path} #{options} #{Shellwords.escape(@file_to_parse)}`
14
- Ffprober::Parsers::Json.new(json_output)
15
- end
16
-
17
- private
6
+ class FileParser
7
+ extend T::Sig
18
8
 
19
- def options
20
- options = "-v quiet -print_format json -show_format -show_streams"
21
- options << " -show_chapters" if ffprobe_version.version >= Gem::Version.new("2.0.0")
22
- options
9
+ sig do
10
+ params(
11
+ file_to_parse: String,
12
+ exec: T.any(Ffprober::Ffmpeg::Exec, T.untyped)
13
+ ).void
23
14
  end
15
+ def initialize(file_to_parse, exec = Ffprober::Ffmpeg::Exec.new)
16
+ raise ArgumentError, "File not found #{file_to_parse}" unless ::File.exist?(file_to_parse)
24
17
 
25
- def ffprobe_version
26
- Ffprober::Ffmpeg::Version.new
18
+ @file_to_parse = file_to_parse
19
+ @exec = exec
27
20
  end
28
21
 
29
- def ffprobe_finder
30
- Ffprober::Ffmpeg::Finder
22
+ sig { returns(Ffprober::Parsers::JsonParser) }
23
+ def load
24
+ JsonParser.new(@exec.json_output(@file_to_parse))
31
25
  end
32
26
  end
33
27
  end
@@ -1,8 +1,12 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
1
4
  module Ffprober
2
5
  module Parsers
3
- class Json
6
+ class JsonParser
4
7
  def initialize(json_to_parse)
5
- fail ArgumentError.new("No JSON input data") if json_to_parse.nil?
8
+ raise ArgumentError, 'No JSON input data' if json_to_parse.nil?
9
+
6
10
  @json_to_parse = json_to_parse
7
11
  end
8
12
 
@@ -0,0 +1,29 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ require 'uri'
5
+
6
+ module Ffprober
7
+ module Parsers
8
+ class UrlParser
9
+ VALID_URI_REGEX = /\A#{URI::DEFAULT_PARSER.make_regexp}\z/.freeze
10
+
11
+ def initialize(url_to_parse, exec = Ffprober::Ffmpeg::Exec.new)
12
+ raise ArgumentError, "#{url_to_parse} is not a valid URL" unless valid_url?(url_to_parse)
13
+
14
+ @url_to_parse = url_to_parse
15
+ @exec = exec
16
+ end
17
+
18
+ def load
19
+ JsonParser.new(@exec.json_output(@url_to_parse))
20
+ end
21
+
22
+ private
23
+
24
+ def valid_url?(url)
25
+ url.gsub(' ', '%20') =~ VALID_URI_REGEX
26
+ end
27
+ end
28
+ end
29
+ end
@@ -1,3 +1,6 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
1
4
  module Ffprober
2
5
  class Stream
3
6
  include Ffprober::DynamicInitializer
@@ -1,3 +1,6 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
1
4
  module Ffprober
2
5
  class SubtitleStream < Stream
3
6
  end
@@ -1,3 +1,6 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
1
4
  module Ffprober
2
- VERSION = "0.4.6"
5
+ VERSION = '1.0'
3
6
  end
@@ -1,3 +1,6 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
1
4
  module Ffprober
2
5
  class VideoStream < Stream
3
6
  end
@@ -1,31 +1,61 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
1
4
  module Ffprober
2
5
  class Wrapper
6
+ extend T::Sig
7
+
8
+ attr_reader :json
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 }
3
15
  def initialize(json)
4
- @json = json
5
- end
16
+ raise FfprobeError, json[:error] if json[:error]
6
17
 
7
- def format
8
- @format ||= Ffprober::Format.new(json[: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]))
9
25
  end
26
+ # rubocop:enable Metrics/AbcSize
10
27
 
28
+ sig { returns(T::Array[Ffprober::VideoStream]) }
11
29
  def video_streams
12
- @video_streams ||= stream_by_codec("video").map { |data| Ffprober::VideoStream.new(data) }
30
+ @video_streams ||= stream_by_codec('video').map do |data|
31
+ VideoStream.new(data)
32
+ end
13
33
  end
14
34
 
35
+ sig { returns(T::Array[Ffprober::AudioStream]) }
15
36
  def audio_streams
16
- @audio_streams ||= stream_by_codec("audio").map { |data| Ffprober::AudioStream.new(data) }
37
+ @audio_streams ||= stream_by_codec('audio').map do |data|
38
+ AudioStream.new(data)
39
+ end
17
40
  end
18
41
 
42
+ sig { returns(T::Array[Ffprober::DataStream]) }
19
43
  def data_streams
20
- @data_streams ||= stream_by_codec("data").map { |data| Ffprober::DataStream.new(data) }
44
+ @data_streams ||= stream_by_codec('data').map do |data|
45
+ DataStream.new(data)
46
+ end
21
47
  end
22
48
 
49
+ sig { returns(T::Array[Ffprober::Chapter]) }
23
50
  def chapters
24
- @chapters ||= json[:chapters].map { |chapter| Ffprober::Chapter.new(chapter) }
51
+ @chapters ||= json[:chapters].map { |chapter| Chapter.new(chapter) }
25
52
  end
26
53
 
54
+ sig { returns(T::Array[Ffprober::SubtitleStream]) }
27
55
  def subtitle_streams
28
- @subtitle_streams ||= stream_by_codec("subtitle").map { |stream| Ffprober::SubtitleStream.new(stream) }
56
+ @subtitle_streams ||= stream_by_codec('subtitle').map do |stream|
57
+ SubtitleStream.new(stream)
58
+ end
29
59
  end
30
60
 
31
61
  private
@@ -37,9 +67,5 @@ module Ffprober
37
67
  def streams
38
68
  json[:streams]
39
69
  end
40
-
41
- def json
42
- @json
43
- end
44
70
  end
45
71
  end
metadata CHANGED
@@ -1,43 +1,127 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ffprober
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.6
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: 2015-11-12 00:00:00.000000000 Z
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
16
44
  requirements:
17
45
  - - "~>"
18
46
  - !ruby/object:Gem::Version
19
- version: '10.0'
47
+ version: '12.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '12.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1'
20
62
  type: :development
21
63
  prerelease: false
22
64
  version_requirements: !ruby/object:Gem::Requirement
23
65
  requirements:
24
66
  - - "~>"
25
67
  - !ruby/object:Gem::Version
26
- version: '10.0'
68
+ version: '1'
27
69
  - !ruby/object:Gem::Dependency
28
- name: rspec
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
29
113
  requirement: !ruby/object:Gem::Requirement
30
114
  requirements:
31
115
  - - "~>"
32
116
  - !ruby/object:Gem::Version
33
- version: '3.0'
117
+ version: '0.19'
34
118
  type: :development
35
119
  prerelease: false
36
120
  version_requirements: !ruby/object:Gem::Requirement
37
121
  requirements:
38
122
  - - "~>"
39
123
  - !ruby/object:Gem::Version
40
- version: '3.0'
124
+ version: '0.19'
41
125
  description: a Ruby wrapper for ffprobe
42
126
  email:
43
127
  - beanie@benle.de
@@ -45,26 +129,19 @@ executables: []
45
129
  extensions: []
46
130
  extra_rdoc_files: []
47
131
  files:
48
- - ".gitignore"
49
- - ".rspec"
50
- - ".rubocop.yml"
51
- - ".ruby-version"
52
- - ".travis.yml"
53
132
  - CODE_OF_CONDUCT.md
54
133
  - CONTRIBUTING.md
55
134
  - Changes.md
56
135
  - Gemfile
57
136
  - LICENSE
58
137
  - README.md
59
- - Rakefile
60
- - examples/from_file.rb
61
138
  - ffprober.gemspec
62
139
  - lib/ffprober.rb
63
140
  - lib/ffprober/audio_stream.rb
64
141
  - lib/ffprober/chapter.rb
65
142
  - lib/ffprober/data_stream.rb
66
143
  - lib/ffprober/dynamic_initializer.rb
67
- - lib/ffprober/errors.rb
144
+ - lib/ffprober/ffmpeg/exec.rb
68
145
  - lib/ffprober/ffmpeg/finder.rb
69
146
  - lib/ffprober/ffmpeg/version.rb
70
147
  - lib/ffprober/ffmpeg/version_validator.rb
@@ -73,6 +150,7 @@ files:
73
150
  - lib/ffprober/parser.rb
74
151
  - lib/ffprober/parsers/file.rb
75
152
  - lib/ffprober/parsers/json.rb
153
+ - lib/ffprober/parsers/url.rb
76
154
  - lib/ffprober/stream.rb
77
155
  - lib/ffprober/subtitle_stream.rb
78
156
  - lib/ffprober/version.rb
@@ -82,13 +160,13 @@ homepage: https://github.com/beanieboi/ffprober
82
160
  licenses:
83
161
  - MIT
84
162
  metadata: {}
85
- post_install_message:
163
+ post_install_message:
86
164
  rdoc_options: []
87
165
  require_paths:
88
166
  - lib
89
167
  required_ruby_version: !ruby/object:Gem::Requirement
90
168
  requirements:
91
- - - "~>"
169
+ - - ">="
92
170
  - !ruby/object:Gem::Version
93
171
  version: '2.0'
94
172
  required_rubygems_version: !ruby/object:Gem::Requirement
@@ -97,10 +175,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
97
175
  - !ruby/object:Gem::Version
98
176
  version: '0'
99
177
  requirements: []
100
- rubyforge_project:
101
- rubygems_version: 2.4.5
102
- signing_key:
178
+ rubygems_version: 3.1.4
179
+ signing_key:
103
180
  specification_version: 4
104
181
  summary: a Ruby wrapper for ffprobe (part of ffmpeg)
105
182
  test_files: []
106
- has_rdoc: