ffprober 0.4.6 → 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.
@@ -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: