alacit 0.1.1 → 1.0.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.
- data/CHANGELOG.md +33 -0
- data/{README.markdown → README.md} +5 -0
- data/alacit.gemspec +2 -2
- data/lib/alacit.rb +70 -23
- data/lib/cuesheet.rb +92 -0
- data/lib/index.rb +112 -0
- data/lib/version.rb +1 -1
- data/pkg/alacit-0.1.1.gem +0 -0
- data/pkg/alacit-1.0.0.gem +0 -0
- data/test/converter_test.rb +22 -6
- data/test/fixtures/{test.ape → test3.ape} +0 -0
- data/test/fixtures/test3.cue +19 -0
- metadata +15 -7
data/CHANGELOG.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# AlacIt Changelog
|
2
|
+
|
3
|
+
## 1.0.0
|
4
|
+
|
5
|
+
* Cue-Sheet Splitting (Extraction) - If a matching-named `.cue` sheet is found in the same directory as the audio file, then multiple M4A's are generated based on the Cue Sheet data.
|
6
|
+
|
7
|
+
## 0.1.1
|
8
|
+
|
9
|
+
* Fix RubyGems summary and description.
|
10
|
+
|
11
|
+
## 0.1.0
|
12
|
+
|
13
|
+
* APE support
|
14
|
+
|
15
|
+
## 0.0.3
|
16
|
+
|
17
|
+
* Accepts any assortment of files and directories, and it will process them all in batch.
|
18
|
+
* Non-destructive by default. Added `--force` option.
|
19
|
+
* Alacit is now a Gem.
|
20
|
+
* Suppress FFmpeg's loud output.
|
21
|
+
* More UNIX-standard exit codes.
|
22
|
+
* Added Unit tests.
|
23
|
+
* Code is more Object-oriented.
|
24
|
+
* Remove unnecessary install instructions now that it's a Gem.
|
25
|
+
* Fix error in help text.
|
26
|
+
|
27
|
+
## 0.0.2
|
28
|
+
|
29
|
+
* WAV support
|
30
|
+
|
31
|
+
## 0.0.1
|
32
|
+
|
33
|
+
* Convert FLAC files to ALAC M4A's.
|
@@ -6,6 +6,7 @@ Apple Lossless conversion utility. Converts APE, FLAC, and WAV audio files to A
|
|
6
6
|
* No quality loss
|
7
7
|
* Basic metadata survives: Song, Artist, etc.
|
8
8
|
* Converts entire directories, single files, or any combination thereof.
|
9
|
+
* Cue-Sheet splitting / extraction
|
9
10
|
* Puts converted files in same dir as source.
|
10
11
|
|
11
12
|
### Install
|
@@ -51,6 +52,10 @@ AlacIt won't overwrite existing files by default. If you need to, just force ove
|
|
51
52
|
alacit --force song.flac
|
52
53
|
alacit -f song.flac
|
53
54
|
|
55
|
+
#### Cue-Sheet Splitting
|
56
|
+
|
57
|
+
Have you ever downloaded an album and it's a single, large audio file along with a `.cue` file? AlacIt will split that into individual files for you. If a matching-named `.cue` sheet is found in the same directory as the audio file, then multiple M4A's are generated based on the Cue Sheet data.
|
58
|
+
|
54
59
|
### Dependencies
|
55
60
|
|
56
61
|
* **Ruby 1.9.2+**
|
data/alacit.gemspec
CHANGED
@@ -9,8 +9,8 @@ spec = Gem::Specification.new do |s|
|
|
9
9
|
s.email = 'me@russbrooks.com'
|
10
10
|
s.homepage = 'http://russbrooks.com'
|
11
11
|
s.platform = Gem::Platform::RUBY
|
12
|
-
s.summary = 'APE, FLAC, and WAV to Apple Lossless (ALAC) batch conversion utility.'
|
13
|
-
s.description = 'Quickly convert entire directories of APE, FLAC, and WAV files to Apple Lossless (ALAC) for importation into iTunes, iPhones, iPads, and iPods.'
|
12
|
+
s.summary = 'APE, FLAC, and WAV to Apple Lossless (ALAC) batch conversion utility and cue-sheet splitter.'
|
13
|
+
s.description = 'Quickly convert entire directories of APE, FLAC, and WAV files to Apple Lossless (ALAC) for importation into iTunes, iPhones, iPads, and iPods. It does Cue-Sheet splitting too.'
|
14
14
|
s.files = `git ls-files`.split("\n")
|
15
15
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
16
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
data/lib/alacit.rb
CHANGED
@@ -12,9 +12,11 @@
|
|
12
12
|
# On Linux: `sudo apt-get install flac ffmpeg`
|
13
13
|
# Windows : [untested]
|
14
14
|
|
15
|
+
require 'application'
|
16
|
+
require 'cuesheet'
|
17
|
+
require 'index'
|
15
18
|
require 'open3'
|
16
19
|
require 'version'
|
17
|
-
require 'application'
|
18
20
|
|
19
21
|
module AlacIt
|
20
22
|
class Converter < Application
|
@@ -44,22 +46,28 @@ module AlacIt
|
|
44
46
|
|
45
47
|
unless Dir.glob(source_glob).empty?
|
46
48
|
Dir.glob(source_glob) do |file|
|
47
|
-
|
49
|
+
cue_file = file.chomp(File.extname(file)) + '.cue'
|
50
|
+
|
51
|
+
if File.exists? cue_file
|
52
|
+
extract_songs file, cue_file
|
53
|
+
else
|
54
|
+
m4a_file = file.chomp(File.extname(file)) + '.m4a'
|
48
55
|
|
49
|
-
|
50
|
-
|
51
|
-
|
56
|
+
if !File.exists?(m4a_file) || @options[:force]
|
57
|
+
command = 'ffmpeg -y -i "' + file + '" -c:a alac "' + m4a_file + '"'
|
58
|
+
stdout_str, stderr_str, status = Open3.capture3(command)
|
52
59
|
|
53
|
-
|
54
|
-
|
60
|
+
if status.success?
|
61
|
+
puts "#{file} converted."
|
62
|
+
else
|
63
|
+
$stderr.puts "Error: #{file}: File could not be converted."
|
64
|
+
$stderr.puts stderr_str.split("\n").last
|
65
|
+
next
|
66
|
+
end
|
55
67
|
else
|
56
|
-
$stderr.puts "Error: #{
|
57
|
-
$stderr.puts stderr_str.split("\n").last
|
68
|
+
$stderr.puts "Error: \"#{m4a_file}\" exists. Use --force option to overwrite."
|
58
69
|
next
|
59
70
|
end
|
60
|
-
else
|
61
|
-
$stderr.puts "Error: #{m4a_file} exists. Use --force option to overwrite."
|
62
|
-
next
|
63
71
|
end
|
64
72
|
end
|
65
73
|
else
|
@@ -71,22 +79,30 @@ module AlacIt
|
|
71
79
|
def convert_file(file)
|
72
80
|
if File.extname(file) =~ /(\.ape|\.flac|\.wav)/i
|
73
81
|
if File.exists? file
|
74
|
-
|
82
|
+
cue_file = file.chomp(File.extname(file)) + '.cue'
|
75
83
|
|
76
|
-
if
|
77
|
-
|
78
|
-
|
84
|
+
if File.exists? cue_file
|
85
|
+
extract_songs file, cue_file
|
86
|
+
else
|
87
|
+
# File has no Cuesheet. Convert the entire file.
|
88
|
+
m4a_file = file.chomp(File.extname(file)) + '.m4a'
|
89
|
+
|
90
|
+
if !File.exists?(m4a_file) || @options[:force]
|
91
|
+
command = 'ffmpeg -y -i "' + file + '" -c:a alac "' + m4a_file + '"'
|
92
|
+
|
93
|
+
stdout_str, stderr_str, status = Open3.capture3(command)
|
79
94
|
|
80
|
-
|
81
|
-
|
95
|
+
if status.success?
|
96
|
+
puts "#{file} converted."
|
97
|
+
else
|
98
|
+
$stderr.puts "Error: #{file}: File could not be converted."
|
99
|
+
$stderr.puts stderr_str.split("\n").last
|
100
|
+
return
|
101
|
+
end
|
82
102
|
else
|
83
|
-
$stderr.puts "Error: #{
|
84
|
-
$stderr.puts stderr_str.split("\n").last
|
103
|
+
$stderr.puts "Error: \"#{m4a_file}\" exists. Use --force option to overwrite."
|
85
104
|
return
|
86
105
|
end
|
87
|
-
else
|
88
|
-
$stderr.puts "Error: #{m4a_file} exists."
|
89
|
-
return
|
90
106
|
end
|
91
107
|
else
|
92
108
|
$stderr.puts "Error: #{file}: No such file."
|
@@ -97,6 +113,37 @@ module AlacIt
|
|
97
113
|
return
|
98
114
|
end
|
99
115
|
end
|
116
|
+
|
117
|
+
def extract_songs(file, cue_file)
|
118
|
+
cuesheet = AlacIt::Cuesheet.new(File.read(cue_file))
|
119
|
+
cuesheet.parse!
|
120
|
+
|
121
|
+
cuesheet.songs.each do |song|
|
122
|
+
m4a_filename = song[:track].to_s.rjust(2, '0') + ' - ' + song[:title] + '.m4a'
|
123
|
+
m4a_file = File.join(File.dirname(file), m4a_filename)
|
124
|
+
|
125
|
+
if !File.exists?(m4a_file) || @options[:force]
|
126
|
+
command = 'ffmpeg -y'
|
127
|
+
command << ' -i "' + file + '" -c:a alac'
|
128
|
+
command << ' -ss ' + song[:index].to_human_ms
|
129
|
+
command << (song[:duration].nil? ? '' : ' -t ' + song[:duration].to_human_ms)
|
130
|
+
command << ' "' + m4a_file + '"'
|
131
|
+
|
132
|
+
stdout_str, stderr_str, status = Open3.capture3(command)
|
133
|
+
|
134
|
+
if status.success?
|
135
|
+
puts "\"#{m4a_filename}\" extracted based on cue sheet."
|
136
|
+
else
|
137
|
+
$stderr.puts "Error: \"#{m4a_filename}\": File could not be extracted."
|
138
|
+
$stderr.puts stderr_str.split("\n").last
|
139
|
+
next
|
140
|
+
end
|
141
|
+
else
|
142
|
+
$stderr.puts "Error: \"#{m4a_filename}\" exists. Use --force option to overwrite."
|
143
|
+
next
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
100
147
|
end
|
101
148
|
end
|
102
149
|
|
data/lib/cuesheet.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
module AlacIt
|
2
|
+
class Cuesheet
|
3
|
+
attr_reader :cuesheet, :songs, :track_duration
|
4
|
+
|
5
|
+
def initialize(cuesheet, track_duration = nil)
|
6
|
+
@cuesheet = cuesheet
|
7
|
+
@reg = {
|
8
|
+
:track => %r(TRACK (\d{1,3}) AUDIO),
|
9
|
+
:performer => %r(PERFORMER "(.*)"),
|
10
|
+
:title => %r(TITLE "(.*)"),
|
11
|
+
:index => %r(INDEX \d{1,3} (\d{1,3}):(\d{1,2}):(\d{1,2}))
|
12
|
+
}
|
13
|
+
@track_duration = AlacIt::Index.new(track_duration) if track_duration
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse!
|
17
|
+
@songs = parse_titles.map{ |title| {:title => title} }
|
18
|
+
@songs.each_with_index do |song, i|
|
19
|
+
song[:performer] = parse_performers[i]
|
20
|
+
song[:track] = parse_tracks[i]
|
21
|
+
song[:index] = parse_indices[i]
|
22
|
+
end
|
23
|
+
raise AlacIt::InvalidCuesheet.new('Cuesheet is malformed!') unless valid?
|
24
|
+
calculate_song_durations!
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
def position(value)
|
29
|
+
index = Index.new(value)
|
30
|
+
return @songs.first if index < @songs.first[:index]
|
31
|
+
@songs.each_with_index do |song, i|
|
32
|
+
return song if song == @songs.last
|
33
|
+
return song if between(song[:index], @songs[i + 1][:index], index)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def valid?
|
38
|
+
@songs.all? do |song|
|
39
|
+
[:performer, :track, :index, :title].all? do |key|
|
40
|
+
song[key] != nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def calculate_song_durations!
|
48
|
+
@songs.each_with_index do |song, i|
|
49
|
+
if song == @songs.last
|
50
|
+
song[:duration] = (@track_duration - song[:index]) if @track_duration
|
51
|
+
return
|
52
|
+
end
|
53
|
+
song[:duration] = @songs[i + 1][:index] - song[:index]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def between(a, b, position_index)
|
58
|
+
(position_index > a) && (position_index < b)
|
59
|
+
end
|
60
|
+
|
61
|
+
def parse_titles
|
62
|
+
unless @titles
|
63
|
+
@titles = cuesheet_scan(:title).map{ |title| title.first }
|
64
|
+
@titles.delete_at(0)
|
65
|
+
end
|
66
|
+
@titles
|
67
|
+
end
|
68
|
+
|
69
|
+
def parse_performers
|
70
|
+
unless @performers
|
71
|
+
@performers = cuesheet_scan(:performer).map{ |performer| performer.first }
|
72
|
+
@performers.delete_at(0)
|
73
|
+
end
|
74
|
+
@performers
|
75
|
+
end
|
76
|
+
|
77
|
+
def parse_tracks
|
78
|
+
@tracks ||= cuesheet_scan(:track).map{ |track| track.first.to_i }
|
79
|
+
end
|
80
|
+
|
81
|
+
def parse_indices
|
82
|
+
@indices ||= cuesheet_scan(:index).map{ |index| AlacIt::Index.new([index[0].to_i, index[1].to_i, index[2].to_i]) }
|
83
|
+
end
|
84
|
+
|
85
|
+
def cuesheet_scan(field)
|
86
|
+
scan = @cuesheet.scan(@reg[field])
|
87
|
+
raise InvalidCuesheet.new("No fields were found for #{field.to_s}") if scan.empty?
|
88
|
+
scan
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
data/lib/index.rb
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
module AlacIt
|
2
|
+
class Index
|
3
|
+
SECONDS_PER_MINUTE = 60
|
4
|
+
FRAMES_PER_SECOND = 75
|
5
|
+
FRAMES_PER_MINUTE = FRAMES_PER_SECOND * 60
|
6
|
+
|
7
|
+
attr_reader :minutes, :seconds, :frames
|
8
|
+
|
9
|
+
def initialize(value=nil)
|
10
|
+
case value
|
11
|
+
when Array
|
12
|
+
set_from_array!(value)
|
13
|
+
when Integer
|
14
|
+
set_from_integer!(value)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_f
|
19
|
+
((@minutes * SECONDS_PER_MINUTE) + (@seconds) + (@frames.to_f / FRAMES_PER_SECOND)).to_f
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_i
|
23
|
+
to_f.floor
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_a
|
27
|
+
[@minutes, @seconds, @frames]
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
"#{'%02d' % @minutes}:#{'%02d' % @seconds}:#{'%02d' % @frames}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_human_ms
|
35
|
+
"00:#{'%02d' % @minutes}:#{'%02d' % @seconds}" + (@frames.to_f / 75).round(3).to_s[1..-1]
|
36
|
+
end
|
37
|
+
|
38
|
+
def +(other)
|
39
|
+
self.class.new(carrying_addition(other))
|
40
|
+
end
|
41
|
+
|
42
|
+
def -(other)
|
43
|
+
self.class.new(carrying_subtraction(other))
|
44
|
+
end
|
45
|
+
|
46
|
+
def >(other)
|
47
|
+
self.to_f > other.to_f
|
48
|
+
end
|
49
|
+
|
50
|
+
def <(other)
|
51
|
+
self.to_f < other.to_f
|
52
|
+
end
|
53
|
+
|
54
|
+
def ==(other)
|
55
|
+
self.to_a == other.to_a
|
56
|
+
end
|
57
|
+
|
58
|
+
def each
|
59
|
+
to_a.each { |value| yield value }
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def carrying_addition(other)
|
65
|
+
minutes, seconds, frames = *[@minutes + other.minutes,
|
66
|
+
@seconds + other.seconds, @frames + other.frames]
|
67
|
+
|
68
|
+
seconds, frames = *convert_with_rate(frames, seconds, FRAMES_PER_SECOND)
|
69
|
+
minutes, seconds = *convert_with_rate(seconds, minutes, SECONDS_PER_MINUTE)
|
70
|
+
[minutes, seconds, frames]
|
71
|
+
end
|
72
|
+
|
73
|
+
def carrying_subtraction(other)
|
74
|
+
seconds = minutes = 0
|
75
|
+
|
76
|
+
my_frames = @frames + (@seconds * FRAMES_PER_SECOND) + (@minutes * FRAMES_PER_MINUTE)
|
77
|
+
other_frames = other.frames + (other.seconds * FRAMES_PER_SECOND) + (other.minutes * FRAMES_PER_MINUTE)
|
78
|
+
frames = my_frames - other_frames
|
79
|
+
|
80
|
+
seconds, frames = *convert_with_rate(frames, seconds, FRAMES_PER_SECOND)
|
81
|
+
minutes, seconds = *convert_with_rate(seconds, minutes, SECONDS_PER_MINUTE)
|
82
|
+
[minutes, seconds, frames]
|
83
|
+
end
|
84
|
+
|
85
|
+
def convert_with_rate(from, to, rate, step=1)
|
86
|
+
while from >= rate
|
87
|
+
to += step
|
88
|
+
from -= rate
|
89
|
+
end
|
90
|
+
[to, from]
|
91
|
+
end
|
92
|
+
|
93
|
+
def set_from_array!(array)
|
94
|
+
if array.size != 3 || array.any?{|element| !element.is_a?(Integer)}
|
95
|
+
raise ArgumentError.new("Must be initialized with an array in the format of [minutes, seconds,frames], all integers")
|
96
|
+
end
|
97
|
+
@minutes, @seconds, @frames = *array
|
98
|
+
end
|
99
|
+
|
100
|
+
def set_from_integer!(seconds)
|
101
|
+
@minutes = 0
|
102
|
+
@frames = 0
|
103
|
+
@seconds = seconds
|
104
|
+
|
105
|
+
while @seconds >= SECONDS_PER_MINUTE
|
106
|
+
@minutes += 1
|
107
|
+
@seconds -= SECONDS_PER_MINUTE
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
data/lib/version.rb
CHANGED
data/pkg/alacit-0.1.1.gem
CHANGED
Binary file
|
Binary file
|
data/test/converter_test.rb
CHANGED
@@ -36,12 +36,12 @@ class AlacItTest < MiniTest::Unit::TestCase
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def test_single_ape
|
39
|
-
FileUtils.cp 'test/fixtures/
|
39
|
+
FileUtils.cp 'test/fixtures/test3.ape', @temp_dir
|
40
40
|
ARGV.clear
|
41
|
-
ARGV << File.join(@temp_dir, '
|
41
|
+
ARGV << File.join(@temp_dir, 'test3.ape')
|
42
42
|
out, = capture_io { @app.convert }
|
43
|
-
assert_match /
|
44
|
-
assert_equal File.exists?(File.join(@temp_dir, '
|
43
|
+
assert_match /test3\.ape converted/, out
|
44
|
+
assert_equal File.exists?(File.join(@temp_dir, 'test3.m4a')), true
|
45
45
|
end
|
46
46
|
|
47
47
|
def test_single_flac
|
@@ -62,6 +62,22 @@ class AlacItTest < MiniTest::Unit::TestCase
|
|
62
62
|
assert_equal File.exists?(File.join(@temp_dir, 'test2.m4a')), true
|
63
63
|
end
|
64
64
|
|
65
|
+
def test_single_ape_with_cue_file
|
66
|
+
FileUtils.cp 'test/fixtures/test3.ape', @temp_dir
|
67
|
+
FileUtils.cp 'test/fixtures/test3.cue', @temp_dir
|
68
|
+
ARGV.clear
|
69
|
+
ARGV << File.join(@temp_dir, 'test3.ape')
|
70
|
+
out, = capture_io { @app.convert }
|
71
|
+
refute_match /test3\.ape converted/, out
|
72
|
+
assert_match /01 - Track1.m4a\" extracted based on cue sheet/, out
|
73
|
+
assert_match /02 - Track2.m4a\" extracted based on cue sheet/, out
|
74
|
+
assert_match /03 - Track3.m4a\" extracted based on cue sheet/, out
|
75
|
+
assert_equal File.exists?(File.join(@temp_dir, 'test3.m4a')), false
|
76
|
+
assert_equal File.exists?(File.join(@temp_dir, '01 - Track1.m4a')), true
|
77
|
+
assert_equal File.exists?(File.join(@temp_dir, '02 - Track2.m4a')), true
|
78
|
+
assert_equal File.exists?(File.join(@temp_dir, '03 - Track3.m4a')), true
|
79
|
+
end
|
80
|
+
|
65
81
|
def test_mixed_directory
|
66
82
|
FileUtils.cp 'test/fixtures/test.flac', @temp_dir
|
67
83
|
FileUtils.cp 'test/fixtures/test2.wav', @temp_dir
|
@@ -80,7 +96,7 @@ class AlacItTest < MiniTest::Unit::TestCase
|
|
80
96
|
ARGV.clear
|
81
97
|
ARGV << File.join(@temp_dir, 'test.flac')
|
82
98
|
out, err = capture_io { @app.convert }
|
83
|
-
assert_match /test\.m4a exists/, err
|
99
|
+
assert_match /test\.m4a\" exists/, err
|
84
100
|
end
|
85
101
|
|
86
102
|
def test_single_flac_file_exists_force_overwrite
|
@@ -100,7 +116,7 @@ class AlacItTest < MiniTest::Unit::TestCase
|
|
100
116
|
ARGV.clear
|
101
117
|
ARGV << File.join(@temp_dir)
|
102
118
|
out, err = capture_io { @app.convert }
|
103
|
-
assert_match /test\.m4a exists/, err
|
119
|
+
assert_match /test\.m4a\" exists/, err
|
104
120
|
assert_match /test2\.wav converted/, out
|
105
121
|
assert_equal File.exists?(File.join(@temp_dir, 'test2.m4a')), true
|
106
122
|
end
|
File without changes
|
@@ -0,0 +1,19 @@
|
|
1
|
+
REM GENRE "Techno"
|
2
|
+
REM DATE 2012
|
3
|
+
REM DISCID CF0A720E
|
4
|
+
REM COMMENT "ExactAudioCopy v0.99pb5"
|
5
|
+
PERFORMER "Vader"
|
6
|
+
TITLE "Test Title"
|
7
|
+
FILE "test3.ape" WAVE
|
8
|
+
TRACK 01 AUDIO
|
9
|
+
TITLE "Track1"
|
10
|
+
PERFORMER "Faithless"
|
11
|
+
INDEX 01 00:00:00
|
12
|
+
TRACK 02 AUDIO
|
13
|
+
TITLE "Track2"
|
14
|
+
PERFORMER "Faithless"
|
15
|
+
INDEX 01 00:30:74
|
16
|
+
TRACK 03 AUDIO
|
17
|
+
TITLE "Track3"
|
18
|
+
PERFORMER "Faithless"
|
19
|
+
INDEX 01 00:60:39
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alacit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-04-
|
12
|
+
date: 2012-04-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -28,32 +28,38 @@ dependencies:
|
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '0'
|
30
30
|
description: Quickly convert entire directories of APE, FLAC, and WAV files to Apple
|
31
|
-
Lossless (ALAC) for importation into iTunes, iPhones, iPads, and iPods.
|
31
|
+
Lossless (ALAC) for importation into iTunes, iPhones, iPads, and iPods. It does
|
32
|
+
Cue-Sheet splitting too.
|
32
33
|
email: me@russbrooks.com
|
33
34
|
executables:
|
34
35
|
- alacit
|
35
36
|
extensions: []
|
36
37
|
extra_rdoc_files: []
|
37
38
|
files:
|
39
|
+
- CHANGELOG.md
|
38
40
|
- Gemfile
|
39
41
|
- Gemfile.lock
|
40
42
|
- LICENSE.txt
|
41
|
-
- README.
|
43
|
+
- README.md
|
42
44
|
- Rakefile
|
43
45
|
- alacit.gemspec
|
44
46
|
- bin/alacit
|
45
47
|
- lib/alacit.rb
|
46
48
|
- lib/application.rb
|
49
|
+
- lib/cuesheet.rb
|
50
|
+
- lib/index.rb
|
47
51
|
- lib/version.rb
|
48
52
|
- pkg/alacit-0.0.2.gem
|
49
53
|
- pkg/alacit-0.0.3.gem
|
50
54
|
- pkg/alacit-0.1.0.gem
|
51
55
|
- pkg/alacit-0.1.1.gem
|
56
|
+
- pkg/alacit-1.0.0.gem
|
52
57
|
- test/converter_test.rb
|
53
|
-
- test/fixtures/test.ape
|
54
58
|
- test/fixtures/test.flac
|
55
59
|
- test/fixtures/test.m4a
|
56
60
|
- test/fixtures/test2.wav
|
61
|
+
- test/fixtures/test3.ape
|
62
|
+
- test/fixtures/test3.cue
|
57
63
|
homepage: http://russbrooks.com
|
58
64
|
licenses: []
|
59
65
|
post_install_message:
|
@@ -77,10 +83,12 @@ rubyforge_project:
|
|
77
83
|
rubygems_version: 1.8.21
|
78
84
|
signing_key:
|
79
85
|
specification_version: 3
|
80
|
-
summary: APE, FLAC, and WAV to Apple Lossless (ALAC) batch conversion utility
|
86
|
+
summary: APE, FLAC, and WAV to Apple Lossless (ALAC) batch conversion utility and
|
87
|
+
cue-sheet splitter.
|
81
88
|
test_files:
|
82
89
|
- test/converter_test.rb
|
83
|
-
- test/fixtures/test.ape
|
84
90
|
- test/fixtures/test.flac
|
85
91
|
- test/fixtures/test.m4a
|
86
92
|
- test/fixtures/test2.wav
|
93
|
+
- test/fixtures/test3.ape
|
94
|
+
- test/fixtures/test3.cue
|