rtrack 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2d02c55bbd7729e987cdcb9f0c13b425ae9b3f7d
4
+ data.tar.gz: 8ffdfc4796d22c2703aff633bfc0cbbba2dd6e1a
5
+ SHA512:
6
+ metadata.gz: 54457b9e1da6673b26a189067266bdc90d6226a278e05d196491b93a111bd7c8d93c190fd231992447f11080473258487b46418755edd65d223e9a998183547d
7
+ data.tar.gz: 9b9c94fb0aa422bb8d8e1c68004ff1e8e2aff86a761a71f71b9386e82321b21572ed5d9fd1523fc48525f6105d41563ac8c34fc8eccf74ac05cadd5846b1de31
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rtrack.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 marcwebbie
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.
@@ -0,0 +1,133 @@
1
+ # Rtrack
2
+
3
+ RTrack is a object-oriented wrapper around ffmpeg to manipulate audiofiles easily from ruby code.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'rtrack'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install rtrack
18
+
19
+ ## Usage
20
+
21
+ Open a wave file
22
+
23
+ ```ruby
24
+ require 'rtrack'
25
+
26
+ song = AudioTrack.from_file "never_gonna_give_you_up.wav"
27
+ ```
28
+
29
+ ...or a mp3 file
30
+
31
+
32
+ ```ruby
33
+ require 'rtrack'
34
+
35
+ song = AudioTrack.from_file "never_gonna_give_you_up.mp3"
36
+ ```
37
+
38
+ ... or an ogg, or flv, or [anything else ffmpeg supports](http://www.ffmpeg.org/general.html#File-Formats)
39
+
40
+ ```ruby
41
+ ogg_version = AudioTrack.from_file "never_gonna_give_you_up.ogg"
42
+ flv_version = AudioTrack.from_file "never_gonna_give_you_up.flv"
43
+ mp4_version = AudioTrack.from_file "never_gonna_give_you_up.mp4"
44
+ wma_version = AudioTrack.from_file "never_gonna_give_you_up.wma"
45
+ aac_version = AudioTrack.from_file "never_gonna_give_you_up.aiff"
46
+ ```
47
+
48
+ You can concatenate multiple AudioTracks together
49
+
50
+ ```ruby
51
+ song_one = AudioTrack.from_file "one_love.mp3"
52
+ song_two = AudioTrack.from_file "jamming.ogg"
53
+
54
+ song_three = song_one + song_two
55
+
56
+ song_four = song_one + song_two + song_three + AudioTrack.from_file "buffallo_soldiers.mp3"
57
+ ```
58
+
59
+ Get a slice of a track, first 10 seconds
60
+
61
+ ```ruby
62
+ song = AudioTrack.from_file "mozart.mp3"
63
+ slice = song[10000] # rtrack works on milliseconds
64
+ ```
65
+
66
+ Wonder how long is that song?
67
+
68
+ ```
69
+ song = AudioTrack.from_file "jamming.mp3"
70
+ puts song.seconds
71
+ ```
72
+
73
+ Repeat track 4 times
74
+
75
+ ```ruby
76
+ beat = AudioTrack.from_file "beat.wav"
77
+ remix = beat * 4
78
+ ```
79
+
80
+ Save the result to disk
81
+
82
+ ```ruby
83
+ remix.export "remix.mp3", "mp3"
84
+ # or
85
+ remix.save "remix.mp3", "mp3"
86
+ ```
87
+
88
+ Save the results with bitrate
89
+
90
+ ```ruby
91
+ remix.export "remix.mp3", "mp3", "192k"
92
+ ```
93
+
94
+ ## Examples
95
+
96
+ Let's suppose you have plenty of `mp4` videos that you'd like to convert to
97
+ `mp3` so you can listen on your mp3 player on the road.
98
+
99
+ ```ruby
100
+ require "rtrack"
101
+
102
+ Dir[Dir.home + "/Videos/*.mp4"].each do |video_path|
103
+ video_name = File.basename(video_path, File.extname(video_path))
104
+ puts "converting #{video_name}"
105
+ song = AudioTrack.from_file video_path
106
+ song.export "#{video_name}.mp3"
107
+ end
108
+ ```
109
+
110
+ ## Dependencies
111
+
112
+ Requires ffmpeg or avconv for encoding and decoding.
113
+
114
+ - ffmpeg (http://www.ffmpeg.org/)
115
+
116
+ -OR-
117
+
118
+ - avconv (http://libav.org/)
119
+
120
+ ## Trivia
121
+
122
+ + RTrack is inspired by [pydub](http://www.github.com/jiaaro/pydub) and [jquery](http://www.jquery.com)
123
+ + As in pydub all AudioTrack objects are [immutable](http://rubylearning.com/satishtalim/mutable_and_immutable_objects.html)
124
+ + As in jquery you can chain operations using AudioTrack objects
125
+
126
+
127
+ ## Contributing
128
+
129
+ 1. Fork it ( http://github.com/marcwebbie/rtrack/fork )
130
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
131
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
132
+ 4. Push to the branch (`git push origin my-new-feature`)
133
+ 5. Create new Pull Request
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << 'test'
7
+ end
8
+
9
+ task :default => :test
@@ -0,0 +1,58 @@
1
+ require "tempfile"
2
+
3
+ require "rtrack/version"
4
+ require "rtrack/transcoder"
5
+
6
+ class AudioTrack
7
+ attr_reader :wavefile, :duration
8
+
9
+ def initialize (wavefile, duration)
10
+ @wavefile = wavefile
11
+ @duration = duration
12
+ end
13
+
14
+ def self.from_file(infile)
15
+ if not (File.exists? infile)
16
+ fail StandardError, "Couldn't find file from path: #{infile}"
17
+ end
18
+ infile = File.open(infile)
19
+ wavefile = Tempfile.new ['','.wav']
20
+ duration = RTrack::Transcoder.to_wave(infile.path, wavefile.path)
21
+ AudioTrack.new wavefile, duration
22
+ end
23
+
24
+ def seconds
25
+ @duration / 1000
26
+ end
27
+
28
+ def path
29
+ @wavefile.path
30
+ end
31
+
32
+ def [](slice_range)
33
+ if not slice_range.class == Range
34
+ fail StandardError, "Invalid slice was given: #{slice_range}"
35
+ end
36
+
37
+ slice_start, slice_end = slice_range.min, slice_range.max
38
+ new_wavefile = Tempfile.new ['','.wav']
39
+ duration = RTrack::Transcoder.to_slice(@wavefile.path,
40
+ new_wavefile.path,
41
+ slice_start,
42
+ slice_end)
43
+
44
+ AudioTrack.new new_wavefile, duration
45
+ end
46
+
47
+ def +(other)
48
+ info = RTrack::Transcoder.concat @wavefile.path, other.wavefile.path
49
+ AudioTrack.new info["wavefile"], info["duration"]
50
+ end
51
+
52
+ def export(outpath, format="mp3", bitrate="128k")
53
+ return_code = RTrack::Transcoder.export(@wavefile.path, outpath, format, bitrate)
54
+ return_code
55
+ end
56
+
57
+ alias_method :save, :export
58
+ end
@@ -0,0 +1,74 @@
1
+
2
+ module RTrack
3
+ class Transcoder
4
+ BIN = "ffmpeg"
5
+ PROBER = "ffprobe"
6
+
7
+ def self._clean_output output
8
+ output.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
9
+ end
10
+
11
+ def self.bin
12
+ @@bin
13
+ end
14
+
15
+ def self.to_milliseconds(hours, mins, secs, msecs=0)
16
+ (hours * 3600000) + (mins * 60000) + (secs * 1000) + msecs
17
+ end
18
+
19
+ def self.parse_duration(output)
20
+ begin
21
+ output = self._clean_output output
22
+ time_string = output.scan(/time\=(\d+:\d+:\d+\.\d+)/).last.last
23
+ rescue NoMethodError
24
+ raise StandardError, "Couldn't parse duration from transcoder output"
25
+ end
26
+
27
+ mobj = time_string.match(/(?<hours>\d+):(?<mins>\d+):(?<secs>\d+)\.(?<msecs>\d+)/)
28
+ hours = mobj["hours"].to_i
29
+ mins = mobj["mins"].to_i
30
+ secs = mobj["secs"].to_i
31
+ msecs = mobj["msecs"].ljust(3, "0").to_i
32
+
33
+ to_milliseconds hours, mins, secs, msecs
34
+ end
35
+
36
+ def self.to_wave(infile_path, wavefile_path)
37
+ cmd = "#{self::BIN} -y -i #{infile_path} -f wav #{wavefile_path} 2>&1"
38
+ output = `#{cmd}`
39
+ self.parse_duration output
40
+ end
41
+
42
+ def self.to_slice(infile_path, wavefile_path, start, to)
43
+ cmd = "#{self::BIN} -y -i #{infile_path} -ss #{start} -to #{to} -f wav #{wavefile_path} 2>&1"
44
+ output = `#{cmd}`
45
+ self.parse_duration output
46
+ end
47
+
48
+ def self.concat(media_one, media_two)
49
+ new_wavefile = Tempfile.new ['','.wav']
50
+ cmd = "#{self::BIN} -y -i #{media_one} -i #{media_two} -filter_complex '[0:0][1:0]concat=n=2:v=0:a=1[out]' -map '[out]' #{new_wavefile.path} 2>&1"
51
+ output = `#{cmd}`
52
+ duration = self.parse_duration output
53
+ {"wavefile" => new_wavefile, "duration" => duration}
54
+ end
55
+
56
+ def self.is_media?(filepath)
57
+ cmd = "#{self::PROBER} #{filepath} >/dev/null 2>&1"
58
+ `#{cmd}`
59
+ $?.success?
60
+ end
61
+
62
+ def self.export(inpath, outpath, format, bitrate)
63
+ cmd = "#{self::BIN} -y -i #{inpath} -f #{format} -b:a #{bitrate} #{outpath} 2>&1"
64
+ `#{cmd}`
65
+ $?.success?
66
+ end
67
+
68
+ def self.info mediapath
69
+ cmd = "#{self::PROBER} -v quiet -print_format json -show_format -show_streams #{mediapath}"
70
+ output = `#{cmd}`
71
+ JSON::parse output
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,3 @@
1
+ module Rtrack
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rtrack/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rtrack"
8
+ spec.version = Rtrack::VERSION
9
+ spec.authors = ["marcwebbie"]
10
+ spec.email = ["marcwebbie@gmail.com"]
11
+ spec.summary = "RTrack is a object-oriented wrapper around ffmpeg to manipulate audiofiles easily from ruby code."
12
+ spec.description = "RTrack is a object-oriented wrapper around ffmpeg to manipulate audiofiles easily from ruby code."
13
+ spec.homepage = "http://github.com/marcwebbie/rtrack"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "pry"
24
+ end
Binary file
File without changes
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,99 @@
1
+ require 'test/unit'
2
+ require 'tempfile'
3
+
4
+ require 'rtrack'
5
+ require 'rtrack/transcoder'
6
+
7
+ class Audiorack_Tests < Test::Unit::TestCase
8
+ def setup
9
+ @track = AudioTrack.from_file "test/data/test.mp3"
10
+ end
11
+
12
+ def test_instantiate_audio_track_from_file
13
+ test_track = AudioTrack.from_file "test/data/test.mp3"
14
+ assert_not_nil test_track
15
+ assert_equal test_track.class, AudioTrack
16
+ end
17
+
18
+ def test_from_file_throw_exception_when_wrong_infile_path_is_given
19
+ assert_raises(StandardError) do
20
+ test_track = AudioTrack.from_file "test/data/wrong_path.mp3"
21
+ assert_not_nil test_track
22
+ end
23
+ end
24
+
25
+ def test_audio_track_has_a_not_nil_wavefile_from_given_infile
26
+ test_track = AudioTrack.from_file "test/data/test.mp3"
27
+ assert_not_nil test_track.wavefile
28
+ end
29
+
30
+ def test_from_file_returns_audio_track_with_valid_wavefile
31
+ test_track = AudioTrack.from_file "test/data/test.mp3"
32
+ wavefile = test_track.wavefile
33
+ assert_respond_to wavefile, "path"
34
+ assert_equal File.exists?(wavefile.path), true
35
+ assert_equal wavefile.path.end_with?(".wav"), true
36
+ end
37
+
38
+ def test_from_file_returns_audio_track_with_expected_duration
39
+ test_track = AudioTrack.from_file "test/data/test.mp3"
40
+ expected_duration = 10040
41
+ assert_respond_to test_track, "duration"
42
+ assert_equal expected_duration, test_track.duration
43
+
44
+ test_track = AudioTrack.from_file "test/data/test2.mp3"
45
+ expected_duration = 5040
46
+ assert_respond_to test_track, "duration"
47
+ assert_equal expected_duration, test_track.duration
48
+ end
49
+
50
+ def test_duration_seconds_match_duration
51
+ assert_respond_to @track, "seconds"
52
+ expected_seconds = @track.duration/1000
53
+ assert_equal expected_seconds, @track.seconds
54
+ end
55
+
56
+ def test_slice_from_song_has_expected_duration
57
+ assert_respond_to @track, "[]"
58
+ expected_seconds = Random.rand(1..10)
59
+
60
+ slice = AudioTrack.from_file(@track.path)[0..expected_seconds]
61
+ assert_equal slice.seconds, expected_seconds
62
+ slice = AudioTrack.from_file(@track.path)[0...expected_seconds]
63
+ assert_equal slice.seconds, expected_seconds-1
64
+ end
65
+
66
+ def test_slice_operation_throws_exception_when_invalid_slice_range_is_given
67
+ assert_raises(StandardError) do
68
+ @track[nil]
69
+ end
70
+
71
+ assert_raises(StandardError) do
72
+ @track[50]
73
+ end
74
+ end
75
+
76
+ def test_concatenate_two_audio_tracks_has_duration_equal_to_sum_of_durations
77
+ track_one = AudioTrack.from_file("test/data/test.mp3")
78
+ track_two = AudioTrack.from_file("test/data/test2.mp3")
79
+
80
+ assert_respond_to track_one, "+"
81
+ track_three = track_one + track_two
82
+ assert_equal track_three.seconds, track_one.seconds + track_two.seconds
83
+ end
84
+
85
+ def test_export_track
86
+ remix = @track + @track
87
+ destination_file = Tempfile.new ["",".mp3"]
88
+
89
+ assert_respond_to remix, "export"
90
+ assert_equal false, RTrack::Transcoder.is_media?(destination_file.path)
91
+ remix.export destination_file.path
92
+ assert_equal true, RTrack::Transcoder.is_media?(destination_file.path)
93
+ end
94
+
95
+ def test_save_is_same_as_export
96
+ assert_respond_to @track, "save"
97
+ assert_equal @track.method(:save), @track.method(:export)
98
+ end
99
+ end
@@ -0,0 +1,31 @@
1
+ require 'test/unit'
2
+ require 'tempfile'
3
+ require 'json'
4
+
5
+ require 'rtrack'
6
+
7
+ class Transcoder_Tests < Test::Unit::TestCase
8
+ def test_transcoder_raises_standard_error_when_missing_time_from_transcoder_output
9
+ assert_raises(StandardError) do
10
+ RTrack::Transcoder.parse_duration "bad output"
11
+ end
12
+ end
13
+
14
+ def test_trascoder_check_if_mp3_is_valid_media
15
+ assert_equal true, RTrack::Transcoder.is_media?("test/data/test2.mp3")
16
+ assert_equal false, RTrack::Transcoder.is_media?("test/data/bad.mp3")
17
+ end
18
+
19
+ def test_transcoder_parse_duration_returns_expected_milliseconds
20
+ mock_output = "time=00:00:10.04"
21
+ expected_milliseconds = 10040
22
+ assert_equal expected_milliseconds, RTrack::Transcoder.parse_duration(mock_output)
23
+ end
24
+
25
+ def test_transcoder_info_returns_expected_hash_with_info_about_media
26
+ assert_respond_to RTrack::Transcoder, "info"
27
+ info = RTrack::Transcoder.info "test/data/test3.mp3"
28
+ assert_equal true, info.keys.include?("streams"), "info doesn't contain streams"
29
+ assert_equal true, info.keys.include?("format"), "info doens't contain formats"
30
+ end
31
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rtrack
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - marcwebbie
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: RTrack is a object-oriented wrapper around ffmpeg to manipulate audiofiles
56
+ easily from ruby code.
57
+ email:
58
+ - marcwebbie@gmail.com
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - Gemfile
65
+ - LICENSE.txt
66
+ - README.md
67
+ - Rakefile
68
+ - lib/rtrack.rb
69
+ - lib/rtrack/transcoder.rb
70
+ - lib/rtrack/version.rb
71
+ - rtrack.gemspec
72
+ - test/data/bach.ogg
73
+ - test/data/bad.mp3
74
+ - test/data/party.mp3
75
+ - test/data/test.mp3
76
+ - test/data/test2.mp3
77
+ - test/data/test3.mp3
78
+ - test/test_rtrack.rb
79
+ - test/test_transcoder.rb
80
+ homepage: http://github.com/marcwebbie/rtrack
81
+ licenses:
82
+ - MIT
83
+ metadata: {}
84
+ post_install_message:
85
+ rdoc_options: []
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ requirements: []
99
+ rubyforge_project:
100
+ rubygems_version: 2.2.2
101
+ signing_key:
102
+ specification_version: 4
103
+ summary: RTrack is a object-oriented wrapper around ffmpeg to manipulate audiofiles
104
+ easily from ruby code.
105
+ test_files:
106
+ - test/data/bach.ogg
107
+ - test/data/bad.mp3
108
+ - test/data/party.mp3
109
+ - test/data/test.mp3
110
+ - test/data/test2.mp3
111
+ - test/data/test3.mp3
112
+ - test/test_rtrack.rb
113
+ - test/test_transcoder.rb