media 0.0.1

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.
data/.gitignore ADDED
@@ -0,0 +1,35 @@
1
+ # See http://help.github.com/ignore-files/ for more about ignoring files.
2
+ #
3
+ # If you find yourself ignoring temporary files generated by your text editor
4
+ # or operating system, you probably want to add a global ignore instead:
5
+ # git config --global core.excludesfile ~/.gitignore
6
+
7
+ # Ignore all of the generated gem stuff
8
+ /pkg
9
+ /*.gem
10
+
11
+ # Ignore bundler config
12
+ /.bundle
13
+ /Gemfile.lock
14
+
15
+ # Ignore all bundler caching
16
+ /vendor/cache
17
+ /vendor/ruby
18
+
19
+ # Ignore all tempfiles
20
+ /tmp
21
+
22
+ # Ignores that should be in the global gitignore
23
+ # /*.rbc
24
+ # /.config
25
+ # /.yardoc
26
+ # /InstalledFiles
27
+ # /_yardoc
28
+ # /coverage/
29
+ # /doc/
30
+ # /lib/bundler/man/
31
+ # /rdoc/
32
+ # /spec/reports/
33
+ # /test/tmp/
34
+ # /test/version_tmp/
35
+ # /coverage
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Jamie Hodge
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # Media
2
+
3
+ An `ffmpeg` or `avconv` wrapper
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'media'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install foo
18
+
19
+ ## Usage
20
+
21
+ Media.convert do
22
+ option 'v', 'warning'
23
+
24
+ input 'in1.mov'
25
+
26
+ input 'in2.mov' do
27
+ option 'foo', 'bar'
28
+ end
29
+
30
+ output 'out.mov' do
31
+ graph do
32
+ chain do
33
+ filter 'split' do
34
+ input 'in'
35
+ output 'T1'
36
+ end
37
+ filter 'fifo'
38
+ filter 'overlay' do
39
+ input 'T2'
40
+ arg '0'
41
+ arg 'H/2'
42
+ output 'out'
43
+ end
44
+ end
45
+ chain do
46
+ filter 'fifo' do
47
+ input 'T1'
48
+ end
49
+ filter 'crop' do
50
+ arg 'iw'
51
+ arg 'ih/2'
52
+ arg '0'
53
+ arg 'ih/2'
54
+ end
55
+ filter 'vflip' do
56
+ output 'T2'
57
+ end
58
+ end
59
+ end
60
+
61
+ map 'out'
62
+
63
+ option 'f', 'prores'
64
+ end
65
+ end
66
+
67
+ Outputs:
68
+
69
+ ffmpeg -v warning -i in1.mov -foo bar -i in2.mov -filter_complex "[in] split [T1], fifo, [T2] overlay=0:H/2 [out]; [T1] fifo, crop=iw:ih/2:0:ih/2, vflip [T2]" -map out -f prores out.mov
70
+
71
+ ## Contributing
72
+
73
+ 1. Fork it
74
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
75
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
76
+ 4. Push to the branch (`git push origin my-new-feature`)
77
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,24 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/clean'
3
+ require 'rake/testtask'
4
+
5
+ begin
6
+ Bundler.setup :default, :development
7
+ rescue Bundler::BundlerError => error
8
+ $stderr.puts error.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit error.status_code
11
+ end
12
+
13
+ Bundler::GemHelper.install_tasks
14
+
15
+ desc 'Run unit tests'
16
+ Rake::TestTask.new do |config|
17
+ config.libs << 'lib' << 'test'
18
+ config.pattern = 'test/**/test_*'
19
+ config.verbose = true
20
+ config.warning = true
21
+ end
22
+
23
+ desc 'Run tests'
24
+ task default: :test
data/lib/media.rb ADDED
@@ -0,0 +1,20 @@
1
+ require_relative 'media/version'
2
+
3
+ require_relative 'media/command'
4
+ require_relative 'media/container'
5
+ require_relative 'media/filter'
6
+ require_relative 'media/input'
7
+ require_relative 'media/label'
8
+ require_relative 'media/option'
9
+ require_relative 'media/output'
10
+ require_relative 'media/size'
11
+
12
+ require_relative 'media/builder/command/converter'
13
+
14
+ module Media
15
+ extend self
16
+
17
+ def convert(&blk)
18
+ Command::Converter.extend(Builder::Command::Converter).build(&blk)
19
+ end
20
+ end
@@ -0,0 +1,54 @@
1
+ require_relative '../../option'
2
+ require_relative '../../input'
3
+ require_relative '../../output'
4
+
5
+ require_relative '../../builder/input'
6
+ require_relative '../../builder/output'
7
+
8
+ module Media
9
+ module Builder
10
+ module Command
11
+ module Converter
12
+
13
+ module ClassMethods
14
+
15
+ def build(&blk)
16
+ converter = new
17
+
18
+ if block_given?
19
+ @context = eval('self', blk.binding)
20
+ converter.instance_eval(&blk)
21
+ end
22
+ converter
23
+ end
24
+ end
25
+
26
+ module InstanceMethods
27
+
28
+ def option(key, value)
29
+ options << Media::Option.new(key: key, value: value)
30
+ end
31
+
32
+ def input(url, &blk)
33
+ inputs << Media::Input.extend(Builder::Input).build(url, &blk)
34
+ end
35
+
36
+ def output(url, &blk)
37
+ outputs << Media::Output.extend(Builder::Output).build(url, &blk)
38
+ end
39
+
40
+ def method_missing(method, *args, &blk)
41
+ @context && @context.send(method, *args, &blk)
42
+ super(method, *args, &blk)
43
+ end
44
+ end
45
+
46
+ def self.extended(receiver)
47
+ receiver.extend(ClassMethods)
48
+ receiver.send(:include, InstanceMethods)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+
@@ -0,0 +1,47 @@
1
+ require_relative '../filter/argument'
2
+
3
+ module Media
4
+ module Builder
5
+ module Filter
6
+
7
+ module ClassMethods
8
+
9
+ def build(name, &blk)
10
+ filter = new(name: name)
11
+
12
+ if block_given?
13
+ @context = eval('self', blk.binding)
14
+ filter.instance_eval(&blk)
15
+ end
16
+ filter
17
+ end
18
+ end
19
+
20
+ module InstanceMethods
21
+
22
+ def input(name)
23
+ inputs << Media::Label.new(name: name)
24
+ end
25
+
26
+ def output(name)
27
+ outputs << Media::Label.new(name: name)
28
+ end
29
+
30
+ def argument(key, value=true)
31
+ arguments << Media::Filter::Argument.new(key: key, value: value)
32
+ end
33
+ alias :arg :argument
34
+
35
+ def method_missing(method, *args, &blk)
36
+ @context && @context.send(method, *args, &blk)
37
+ super
38
+ end
39
+ end
40
+
41
+ def self.extended(receiver)
42
+ receiver.extend(ClassMethods)
43
+ receiver.send(:include, InstanceMethods)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,40 @@
1
+ require_relative '../filter'
2
+
3
+ module Media
4
+ module Builder
5
+ module Filter
6
+ module Chain
7
+
8
+ module ClassMethods
9
+
10
+ def build(&blk)
11
+ chain = new
12
+
13
+ if block_given?
14
+ @context = eval('self', blk.binding)
15
+ chain.instance_eval(&blk)
16
+ end
17
+ chain
18
+ end
19
+ end
20
+
21
+ module InstanceMethods
22
+
23
+ def filter(name, &blk)
24
+ filters << Media::Filter.extend(Filter).build(name, &blk)
25
+ end
26
+
27
+ def method_missing(method, *args, &blk)
28
+ @context && @context.send(method, *args, &blk)
29
+ super
30
+ end
31
+ end
32
+
33
+ def self.extended(receiver)
34
+ receiver.extend(ClassMethods)
35
+ receiver.send(:include, InstanceMethods)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,42 @@
1
+ require_relative '../../filter/chain'
2
+
3
+ require_relative 'chain'
4
+
5
+ module Media
6
+ module Builder
7
+ module Filter
8
+ module Graph
9
+
10
+ module ClassMethods
11
+
12
+ def build(&blk)
13
+ graph = new
14
+
15
+ if block_given?
16
+ @context = eval('self', blk.binding)
17
+ graph.instance_eval(&blk)
18
+ end
19
+ graph
20
+ end
21
+ end
22
+
23
+ module InstanceMethods
24
+
25
+ def chain(&blk)
26
+ chains << Media::Filter::Chain.extend(Chain).build(&blk)
27
+ end
28
+
29
+ def method_missing(method, *args, &blk)
30
+ @context && @context.send(method, *args, &blk)
31
+ super
32
+ end
33
+ end
34
+
35
+ def self.extended(receiver)
36
+ receiver.extend(ClassMethods)
37
+ receiver.send(:include, InstanceMethods)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,45 @@
1
+ require_relative 'filter/graph'
2
+
3
+ module Media
4
+ module Builder
5
+ module Input
6
+
7
+ module ClassMethods
8
+
9
+ def build(url, &blk)
10
+ input = new(url: url)
11
+
12
+ if block_given?
13
+ @context = eval('self', blk.binding)
14
+ input.instance_eval(&blk)
15
+ end
16
+ input
17
+ end
18
+ end
19
+
20
+ module InstanceMethods
21
+
22
+ def option(key, value=true)
23
+ @options << Media::Option.new(key: key, value: value).to_s
24
+ end
25
+
26
+ def graph(&blk)
27
+ @options << Option.new(
28
+ key: 'filter_complex',
29
+ value: Media::Filter::Graph.extend(Filter::Graph).build(&blk)
30
+ )
31
+ end
32
+
33
+ def method_missing(method, *args, &blk)
34
+ @context && @context.send(method, *args, &blk)
35
+ super(method, *args, &blk)
36
+ end
37
+ end
38
+
39
+ def self.extended(receiver)
40
+ receiver.extend(ClassMethods)
41
+ receiver.send(:include, InstanceMethods)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,50 @@
1
+ require_relative '../option'
2
+ require_relative '../filter/graph'
3
+
4
+ require_relative 'filter/graph'
5
+
6
+ module Media
7
+ module Builder
8
+ module Output
9
+
10
+ module ClassMethods
11
+
12
+ def build(url, &blk)
13
+ output = new(url: url)
14
+
15
+ if block_given?
16
+ @context = eval('self', blk.binding)
17
+ output.instance_eval(&blk)
18
+ end
19
+ output
20
+ end
21
+ end
22
+
23
+ module InstanceMethods
24
+
25
+ def option(key, value=true)
26
+ @options << Media::Option.new(key: key, value: value)
27
+ end
28
+
29
+ def map(value)
30
+ @options << Media::Option.new(key: 'map', value: value)
31
+ end
32
+
33
+ def graph(&blk)
34
+ @options << Media::Option.new(key: 'filter_complex',
35
+ value: Media::Filter::Graph.extend(Filter::Graph).build(&blk))
36
+ end
37
+
38
+ def method_missing(method, *args, &blk)
39
+ @context && @context.send(method, *args, &blk)
40
+ super
41
+ end
42
+ end
43
+
44
+ def self.extended(receiver)
45
+ receiver.extend(ClassMethods)
46
+ receiver.send(:include, InstanceMethods)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,2 @@
1
+ require_relative 'command/converter'
2
+ require_relative 'command/probe'
@@ -0,0 +1,27 @@
1
+ require_relative 'subshell'
2
+
3
+ module Media
4
+ module Command
5
+ class Converter
6
+
7
+ attr_accessor :options, :inputs, :outputs
8
+
9
+ def initialize(args={})
10
+ @options = Array args.fetch(:options, [])
11
+ @inputs = Array args.fetch(:inputs, [])
12
+ @outputs = Array args.fetch(:outputs, [])
13
+
14
+ @cmd = args.fetch(:cmd, 'ffmpeg')
15
+ @subshell = args.fetch(:subshell, Subshell)
16
+ end
17
+
18
+ def call
19
+ @subshell.new(cmd: to_s).call
20
+ end
21
+
22
+ def to_s
23
+ [@cmd, options, inputs, outputs].reject(&:empty?).join(' ')
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,24 @@
1
+ require_relative 'subshell'
2
+
3
+ module Media
4
+ module Command
5
+ class Probe
6
+
7
+ def initialize(args)
8
+ @options = Array args.fetch(:options, [])
9
+ @input = args.fetch(:input)
10
+
11
+ @cmd = args.fetch(:cmd, 'ffprobe')
12
+ @subshell = args.fetch(:subshell, Subshell)
13
+ end
14
+
15
+ def call
16
+ @subshell.new(cmd: to_s).call
17
+ end
18
+
19
+ def to_s
20
+ [@cmd, @options, @input].reject(&:empty?).join(' ')
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,26 @@
1
+ require 'open3'
2
+ require 'forwardable'
3
+
4
+ module Media
5
+ module Command
6
+ class Subshell
7
+ extend Forwardable
8
+ def_delegators :status, :pid, :exitstatus, :termsig, :stopsig
9
+
10
+ attr_reader :out, :error, :status
11
+
12
+ def initialize(args)
13
+ @cmd = args.fetch(:cmd)
14
+ end
15
+
16
+ def call
17
+ @out, @error, @status = Open3.capture3(@cmd)
18
+ self
19
+ end
20
+
21
+ def success?
22
+ exitstatus == 0
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,43 @@
1
+ require 'json'
2
+ require 'ostruct'
3
+
4
+ require_relative 'command/probe'
5
+ require_relative 'option'
6
+
7
+ module Media
8
+ class Container
9
+ def initialize(args)
10
+ @input = args.fetch(:input)
11
+ @probe = args.fetch(:probe, Command::Probe)
12
+ end
13
+
14
+ def format
15
+ OpenStruct.new(metadata['format'])
16
+ end
17
+
18
+ def streams(args={})
19
+ type = args.fetch(:type, /.*/)
20
+
21
+ metadata['streams'].select {|s| s['codec_type'].match(type)}.
22
+ map {|s| OpenStruct.new(s)}
23
+ end
24
+
25
+ private
26
+
27
+ def metadata
28
+ @metadata ||= JSON.parse(probe.out)
29
+ end
30
+
31
+ def probe
32
+ @probe.new(input: @input, options: options).call
33
+ end
34
+
35
+ def options
36
+ [
37
+ Option.new(key: 'print_format', value: 'json'),
38
+ Option.new(key: 'show_format'),
39
+ Option.new(key: 'show_streams')
40
+ ]
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,29 @@
1
+ require 'shellwords'
2
+
3
+ require_relative 'filter/argument'
4
+ require_relative 'filter/chain'
5
+ require_relative 'filter/graph'
6
+ require_relative 'label'
7
+
8
+ module Media
9
+ class Filter
10
+ attr_reader :name, :arguments, :inputs, :outputs
11
+
12
+ def initialize(args)
13
+ @name = args.fetch(:name)
14
+ @arguments = Array args.fetch(:arguments, [])
15
+ @inputs = Array args.fetch(:inputs, [])
16
+ @outputs = Array args.fetch(:outputs, [])
17
+ end
18
+
19
+ def to_s
20
+ [inputs, filter, outputs].reject(&:empty?).join(' ')
21
+ end
22
+
23
+ private
24
+
25
+ def filter
26
+ [name, arguments.join(':')].reject(&:empty?).join('=')
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,23 @@
1
+ module Media
2
+ class Filter
3
+ class Argument
4
+ def initialize(args)
5
+ @key = args.fetch(:key)
6
+ @value = args.fetch(:value, true)
7
+ end
8
+
9
+ def to_s
10
+ case @value
11
+ when TrueClass, FalseClass then @key
12
+ else "#{@key}=#{value}"
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def value
19
+ @value.gsub(/([\[\]=;,])/, "\\\\\\1")
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ module Media
2
+ class Filter
3
+ class Chain
4
+ attr_reader :filters
5
+
6
+ def initialize(args={}, &blk)
7
+ @filters = args.fetch(:filters, [])
8
+ end
9
+
10
+ def to_s
11
+ filters.join(', ')
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ require_relative 'chain'
2
+
3
+ module Media
4
+ class Filter
5
+ class Graph
6
+ attr_reader :chains
7
+
8
+ def initialize(args={}, &blk)
9
+ @chains = args.fetch(:chains, [])
10
+ end
11
+
12
+ def to_s
13
+ "\"#{chains.join('; ')}\""
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,23 @@
1
+ require_relative 'option'
2
+ require_relative 'filter/graph'
3
+
4
+ module Media
5
+ class Input
6
+ attr_reader :options
7
+
8
+ def initialize(args)
9
+ @url = args.fetch(:url)
10
+ @options = Array args.fetch(:options, [])
11
+ end
12
+
13
+ def to_s
14
+ [options, url].reject(&:empty?).join(' ')
15
+ end
16
+
17
+ private
18
+
19
+ def url
20
+ Option.new(key: 'i', value: @url).to_s
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,11 @@
1
+ module Media
2
+ class Label
3
+ def initialize(args)
4
+ @name = args.fetch(:name, [])
5
+ end
6
+
7
+ def to_s
8
+ "[#{@name}]"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ module Media
2
+ class Option
3
+ def initialize(args)
4
+ @key = args.fetch(:key)
5
+ @value = args.fetch(:value, true)
6
+ end
7
+
8
+ def to_s
9
+ case @value
10
+ when TrueClass then "-#{@key}"
11
+ when FalseClass then "-no#{@key}"
12
+ else "-#{@key} #{@value}"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ require_relative 'option'
2
+
3
+ module Media
4
+ class Output
5
+
6
+ attr_reader :options
7
+
8
+ def initialize(args, &blk)
9
+ @url = args.fetch(:url)
10
+ @options = Array args.fetch(:options, [])
11
+ end
12
+
13
+ def to_s
14
+ [options, @url].join(' ')
15
+ end
16
+ end
17
+ end
data/lib/media/size.rb ADDED
@@ -0,0 +1,12 @@
1
+ module Media
2
+ class Size
3
+ def initialize(args)
4
+ @width = args.fetch(:width)
5
+ @height = args.fetch(:height)
6
+ end
7
+
8
+ def to_s
9
+ [@width, @height].join('x')
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ module Media
2
+ VERSION = '0.0.1'
3
+ end
data/media.gemspec ADDED
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+ require File.dirname(__FILE__) + '/lib/media/version'
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.name = 'media'
6
+ gem.version = Media::VERSION
7
+ gem.authors = ['Jamie Hodge']
8
+ gem.email = ['jamiehodge@me.com']
9
+ gem.summary = 'FFMPEG/AVConv wrapper'
10
+ gem.description = gem.summary
11
+ gem.homepage = 'https://github.com/jamiehodge/convert'
12
+
13
+ gem.files = `git ls-files`.split($/)
14
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
16
+ gem.require_paths = ['lib']
17
+
18
+ gem.add_development_dependency('rake')
19
+ gem.add_development_dependency('minitest')
20
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'bundler'
2
+ Bundler.setup(:default, :test)
3
+
4
+ require 'minitest/autorun'
@@ -0,0 +1,45 @@
1
+ require 'helper'
2
+ require 'media/command/converter'
3
+
4
+ module Media
5
+ module Command
6
+ class TestConverter < MiniTest::Unit::TestCase
7
+
8
+ def subject(args={})
9
+ @subject ||= Converter.new(args.merge(subshell: subshell))
10
+ end
11
+
12
+ def subshell
13
+ @subshell ||= MiniTest::Mock.new
14
+ end
15
+
16
+ def after
17
+ subshell.verify
18
+ end
19
+
20
+ def test_empty_call
21
+ subshell.expect(:new, subshell, [cmd: 'ffmpeg'])
22
+ subshell.expect(:call, true)
23
+
24
+ subject.call
25
+ end
26
+
27
+ def test_with_options
28
+ assert_equal 'ffmpeg options', subject(options: ['options']).to_s
29
+ end
30
+
31
+ def test_call_with_inputs
32
+ assert_equal 'ffmpeg inputs', subject(inputs: ['inputs']).to_s
33
+ end
34
+
35
+ def test_call_with_outputs
36
+ assert_equal 'ffmpeg outputs', subject(outputs: ['outputs']).to_s
37
+ end
38
+
39
+ def test_call_with_all
40
+ assert_equal 'ffmpeg options inputs outputs',
41
+ subject(options: ['options'], inputs: ['inputs'], outputs: ['outputs']).to_s
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,37 @@
1
+ require 'helper'
2
+ require 'media/command/probe'
3
+
4
+ module Media
5
+ module Command
6
+ class TestProbe < MiniTest::Unit::TestCase
7
+
8
+ def subject(args={})
9
+ @subject ||= Probe.new(args.merge(subshell: subshell))
10
+ end
11
+
12
+ def subshell
13
+ @subshell ||= MiniTest::Mock.new
14
+ end
15
+
16
+ def after
17
+ subshell.verify
18
+ end
19
+
20
+ def test_call
21
+ subshell.expect(:new, subshell, [cmd: 'ffprobe input'])
22
+ subshell.expect(:call, true)
23
+
24
+ subject(input: ['input']).call
25
+ end
26
+
27
+ def test_call_with_input
28
+ assert_equal 'ffprobe input', subject(input: ['input']).to_s
29
+ end
30
+
31
+ def test_call_with_all
32
+ assert_equal 'ffprobe options input',
33
+ subject(options: ['options'], input: ['input']).to_s
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,37 @@
1
+ require 'helper'
2
+ require 'media/command/subshell'
3
+
4
+ module Media
5
+ module Command
6
+ class TestSubshell < MiniTest::Unit::TestCase
7
+
8
+ def subject
9
+ Subshell
10
+ end
11
+
12
+ def test_stdout
13
+ shell = subject.new(cmd: 'echo hello')
14
+
15
+ assert_equal("hello\n", shell.call.out)
16
+ end
17
+
18
+ def test_stderr
19
+ shell = subject.new(cmd: 'echo hello 1>&2')
20
+
21
+ assert_equal("hello\n", shell.call.error)
22
+ end
23
+
24
+ def test_success
25
+ shell = subject.new(cmd: 'true')
26
+
27
+ assert(shell.call.success?)
28
+ end
29
+
30
+ def test_failure
31
+ shell = subject.new(cmd: 'false')
32
+
33
+ refute(shell.call.success?)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,25 @@
1
+ require 'helper'
2
+ require 'media/filter/argument'
3
+
4
+ module Media
5
+ class Filter
6
+ class TestArgument < MiniTest::Unit::TestCase
7
+
8
+ def subject
9
+ Argument
10
+ end
11
+
12
+ def test_option
13
+ assert_equal 'foo=bar', subject.new(key: 'foo', value: 'bar').to_s
14
+ end
15
+
16
+ def test_true_flag
17
+ assert_equal 'foo', subject.new(key: 'foo').to_s
18
+ end
19
+
20
+ def test_value_escaping
21
+ assert_equal 'foo=\[\]\=\;\,', subject.new(key: 'foo', value: '[]=;,').to_s
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,13 @@
1
+ require 'helper'
2
+ require 'media/filter/chain'
3
+
4
+ module Media
5
+ class Filter
6
+ class TestChain < MiniTest::Unit::TestCase
7
+
8
+ def test_to_s
9
+ assert_equal('a, b, c', Chain.new(filters: %w(a b c)).to_s)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'helper'
2
+ require 'media/filter/graph'
3
+
4
+ module Media
5
+ class Filter
6
+ class TestGraph < MiniTest::Unit::TestCase
7
+
8
+ def test_to_s
9
+ assert_equal('"a; b; c"', Graph.new(chains: %w(a b c)).to_s)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ require 'helper'
2
+ require 'media/filter'
3
+
4
+ module Media
5
+ class TestFilter < MiniTest::Unit::TestCase
6
+
7
+ def test_to_s
8
+ filter = Filter.new(
9
+ name: 'name',
10
+ arguments: 'arguments',
11
+ inputs: 'inputs',
12
+ outputs: 'outputs'
13
+ )
14
+
15
+ assert_equal('inputs name=arguments outputs', filter.to_s)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,13 @@
1
+ require 'helper'
2
+ require 'media/input'
3
+
4
+ module Media
5
+ class TestInput < MiniTest::Unit::TestCase
6
+
7
+ def test_to_s
8
+ input = Input.new(url: 'url', options: 'options')
9
+
10
+ assert_equal('options -i url', input.to_s)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ require 'helper'
2
+ require 'media/label'
3
+
4
+ module Media
5
+ class TestLabel < MiniTest::Unit::TestCase
6
+
7
+ def test_to_s
8
+ assert_equal '[foo]', Label.new(name: 'foo').to_s
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,23 @@
1
+ require 'helper'
2
+ require 'media/option'
3
+
4
+ module Media
5
+ class TestOption < MiniTest::Unit::TestCase
6
+
7
+ def subject
8
+ Option
9
+ end
10
+
11
+ def test_option
12
+ assert_equal '-foo bar', subject.new(key: 'foo', value: 'bar').to_s
13
+ end
14
+
15
+ def test_true_flag
16
+ assert_equal '-foo', subject.new(key: 'foo').to_s
17
+ end
18
+
19
+ def test_false_flag
20
+ assert_equal '-nofoo', subject.new(key: 'foo', value: false).to_s
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,13 @@
1
+ require 'helper'
2
+ require 'media/output'
3
+
4
+ module Media
5
+ class TestOutput < MiniTest::Unit::TestCase
6
+
7
+ def test_to_s
8
+ output = Output.new(url: 'url', options: 'options')
9
+
10
+ assert_equal('options url', output.to_s)
11
+ end
12
+ end
13
+ end
metadata ADDED
@@ -0,0 +1,187 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: media
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Jamie Hodge
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-12 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ prerelease: false
16
+ type: :development
17
+ name: rake
18
+ requirement: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ none: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ! '>='
27
+ - !ruby/object:Gem::Version
28
+ version: '0'
29
+ none: false
30
+ - !ruby/object:Gem::Dependency
31
+ prerelease: false
32
+ type: :development
33
+ name: minitest
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ none: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ none: false
46
+ description: FFMPEG/AVConv wrapper
47
+ email:
48
+ - jamiehodge@me.com
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - !binary |-
54
+ LmdpdGlnbm9yZQ==
55
+ - !binary |-
56
+ R2VtZmlsZQ==
57
+ - !binary |-
58
+ TElDRU5TRS50eHQ=
59
+ - !binary |-
60
+ UkVBRE1FLm1k
61
+ - !binary |-
62
+ UmFrZWZpbGU=
63
+ - !binary |-
64
+ bGliL21lZGlhLnJi
65
+ - !binary |-
66
+ bGliL21lZGlhL2J1aWxkZXIvY29tbWFuZC9jb252ZXJ0ZXIucmI=
67
+ - !binary |-
68
+ bGliL21lZGlhL2J1aWxkZXIvZmlsdGVyLnJi
69
+ - !binary |-
70
+ bGliL21lZGlhL2J1aWxkZXIvZmlsdGVyL2NoYWluLnJi
71
+ - !binary |-
72
+ bGliL21lZGlhL2J1aWxkZXIvZmlsdGVyL2dyYXBoLnJi
73
+ - !binary |-
74
+ bGliL21lZGlhL2J1aWxkZXIvaW5wdXQucmI=
75
+ - !binary |-
76
+ bGliL21lZGlhL2J1aWxkZXIvb3V0cHV0LnJi
77
+ - !binary |-
78
+ bGliL21lZGlhL2NvbW1hbmQucmI=
79
+ - !binary |-
80
+ bGliL21lZGlhL2NvbW1hbmQvY29udmVydGVyLnJi
81
+ - !binary |-
82
+ bGliL21lZGlhL2NvbW1hbmQvcHJvYmUucmI=
83
+ - !binary |-
84
+ bGliL21lZGlhL2NvbW1hbmQvc3Vic2hlbGwucmI=
85
+ - !binary |-
86
+ bGliL21lZGlhL2NvbnRhaW5lci5yYg==
87
+ - !binary |-
88
+ bGliL21lZGlhL2ZpbHRlci5yYg==
89
+ - !binary |-
90
+ bGliL21lZGlhL2ZpbHRlci9hcmd1bWVudC5yYg==
91
+ - !binary |-
92
+ bGliL21lZGlhL2ZpbHRlci9jaGFpbi5yYg==
93
+ - !binary |-
94
+ bGliL21lZGlhL2ZpbHRlci9ncmFwaC5yYg==
95
+ - !binary |-
96
+ bGliL21lZGlhL2lucHV0LnJi
97
+ - !binary |-
98
+ bGliL21lZGlhL2xhYmVsLnJi
99
+ - !binary |-
100
+ bGliL21lZGlhL29wdGlvbi5yYg==
101
+ - !binary |-
102
+ bGliL21lZGlhL291dHB1dC5yYg==
103
+ - !binary |-
104
+ bGliL21lZGlhL3NpemUucmI=
105
+ - !binary |-
106
+ bGliL21lZGlhL3ZlcnNpb24ucmI=
107
+ - !binary |-
108
+ bWVkaWEuZ2Vtc3BlYw==
109
+ - !binary |-
110
+ dGVzdC9oZWxwZXIucmI=
111
+ - !binary |-
112
+ dGVzdC9tZWRpYS9jb21tYW5kL3Rlc3RfY29udmVydGVyLnJi
113
+ - !binary |-
114
+ dGVzdC9tZWRpYS9jb21tYW5kL3Rlc3RfcHJvYmUucmI=
115
+ - !binary |-
116
+ dGVzdC9tZWRpYS9jb21tYW5kL3Rlc3Rfc3Vic2hlbGwucmI=
117
+ - !binary |-
118
+ dGVzdC9tZWRpYS9maWx0ZXIvdGVzdF9hcmd1bWVudC5yYg==
119
+ - !binary |-
120
+ dGVzdC9tZWRpYS9maWx0ZXIvdGVzdF9jaGFpbi5yYg==
121
+ - !binary |-
122
+ dGVzdC9tZWRpYS9maWx0ZXIvdGVzdF9ncmFwaC5yYg==
123
+ - !binary |-
124
+ dGVzdC9tZWRpYS90ZXN0X2ZpbHRlci5yYg==
125
+ - !binary |-
126
+ dGVzdC9tZWRpYS90ZXN0X2lucHV0LnJi
127
+ - !binary |-
128
+ dGVzdC9tZWRpYS90ZXN0X2xhYmVsLnJi
129
+ - !binary |-
130
+ dGVzdC9tZWRpYS90ZXN0X29wdGlvbi5yYg==
131
+ - !binary |-
132
+ dGVzdC9tZWRpYS90ZXN0X291dHB1dC5yYg==
133
+ homepage: https://github.com/jamiehodge/convert
134
+ licenses: []
135
+ post_install_message:
136
+ rdoc_options: []
137
+ require_paths:
138
+ - lib
139
+ required_ruby_version: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ! '>='
142
+ - !ruby/object:Gem::Version
143
+ segments:
144
+ - 0
145
+ hash: 2002549777813010636
146
+ version: '0'
147
+ none: false
148
+ required_rubygems_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ! '>='
151
+ - !ruby/object:Gem::Version
152
+ segments:
153
+ - 0
154
+ hash: 2002549777813010636
155
+ version: '0'
156
+ none: false
157
+ requirements: []
158
+ rubyforge_project:
159
+ rubygems_version: 1.8.24
160
+ signing_key:
161
+ specification_version: 3
162
+ summary: FFMPEG/AVConv wrapper
163
+ test_files:
164
+ - !binary |-
165
+ dGVzdC9oZWxwZXIucmI=
166
+ - !binary |-
167
+ dGVzdC9tZWRpYS9jb21tYW5kL3Rlc3RfY29udmVydGVyLnJi
168
+ - !binary |-
169
+ dGVzdC9tZWRpYS9jb21tYW5kL3Rlc3RfcHJvYmUucmI=
170
+ - !binary |-
171
+ dGVzdC9tZWRpYS9jb21tYW5kL3Rlc3Rfc3Vic2hlbGwucmI=
172
+ - !binary |-
173
+ dGVzdC9tZWRpYS9maWx0ZXIvdGVzdF9hcmd1bWVudC5yYg==
174
+ - !binary |-
175
+ dGVzdC9tZWRpYS9maWx0ZXIvdGVzdF9jaGFpbi5yYg==
176
+ - !binary |-
177
+ dGVzdC9tZWRpYS9maWx0ZXIvdGVzdF9ncmFwaC5yYg==
178
+ - !binary |-
179
+ dGVzdC9tZWRpYS90ZXN0X2ZpbHRlci5yYg==
180
+ - !binary |-
181
+ dGVzdC9tZWRpYS90ZXN0X2lucHV0LnJi
182
+ - !binary |-
183
+ dGVzdC9tZWRpYS90ZXN0X2xhYmVsLnJi
184
+ - !binary |-
185
+ dGVzdC9tZWRpYS90ZXN0X29wdGlvbi5yYg==
186
+ - !binary |-
187
+ dGVzdC9tZWRpYS90ZXN0X291dHB1dC5yYg==