ruby-audioinfo 0.2.3 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/History.txt +8 -0
- data/Manifest.txt +1 -0
- data/Rakefile +2 -2
- data/lib/audioinfo.rb +78 -10
- data/lib/audioinfo/case_insensitive_hash.rb +16 -0
- data/test/test_audioinfo.rb +35 -0
- data/test/test_case_insensitive_hash.rb +28 -0
- data/test/test_helper.rb +1 -0
- metadata +75 -48
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: be66808c6cbe04237d1052537ff0ad4fc2f3f614
|
4
|
+
data.tar.gz: b2843c08fe747e1c77cc94490ca266559539bc45
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8838cdedf9de87e385559086a0dbafd9bb315b3d8254673c0441ef234d9769435c4c3ee34bc88c2325e15d7a1f7108e8efd684e051e054ccbc75441550a45003
|
7
|
+
data.tar.gz: bf2999b9756f2ec4e986e28fdce3d2d169917802b99c1b565db5ed9d60bf1ceb70e2fe21a473b04af097e400c41eb64c7c9779514ba22f2bcc8d95238b6e2f9f
|
data/History.txt
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
=== 0.3 / 2013-03-26
|
2
|
+
|
3
|
+
* correctly computes bitrate on .flac files
|
4
|
+
* string encoding fixes on .flac files
|
5
|
+
* write support on .flac with "metaflac" binary
|
6
|
+
* case insensitive wrapper to flacinfo's tags hash
|
7
|
+
* uses "ffmpeg" binary for writing tags on not natively supported format
|
8
|
+
|
1
9
|
=== 0.2.3 / 2012-05-24
|
2
10
|
|
3
11
|
* fixed title method on AudioInfo::Album, now returns nil if title is not found
|
data/Manifest.txt
CHANGED
data/Rakefile
CHANGED
@@ -17,8 +17,8 @@ Hoe.spec('ruby-audioinfo') do
|
|
17
17
|
self.test_globs = ["test/test_*.rb"]
|
18
18
|
self.rsync_args = "-rv --delete"
|
19
19
|
|
20
|
-
extra_deps << ['ruby-mp3info', '>= 0.
|
21
|
-
extra_deps << ['ruby-ogginfo', '>= 0.6.
|
20
|
+
extra_deps << ['ruby-mp3info', '>= 0.8']
|
21
|
+
extra_deps << ['ruby-ogginfo', '>= 0.6.11']
|
22
22
|
extra_deps << ['mp4info', '>= 1.7.3']
|
23
23
|
extra_deps << ['moumar-wmainfo-rb', '>= 0.7']
|
24
24
|
extra_deps << ['flacinfo-rb', '>= 0.4']
|
data/lib/audioinfo.rb
CHANGED
@@ -11,6 +11,7 @@ require "apetag"
|
|
11
11
|
$: << File.expand_path(File.dirname(__FILE__))
|
12
12
|
|
13
13
|
require "audioinfo/mpcinfo"
|
14
|
+
require "audioinfo/case_insensitive_hash"
|
14
15
|
|
15
16
|
class AudioInfoError < StandardError ; end
|
16
17
|
|
@@ -35,10 +36,13 @@ class AudioInfo
|
|
35
36
|
|
36
37
|
SUPPORTED_EXTENSIONS = %w{mp3 ogg mpc wma mp4 aac m4a flac}
|
37
38
|
|
38
|
-
VERSION = "0.
|
39
|
+
VERSION = "0.3.1"
|
39
40
|
|
40
41
|
attr_reader :path, :extension, :musicbrainz_infos, :tracknum, :bitrate, :vbr
|
41
42
|
attr_reader :artist, :album, :title, :length, :date
|
43
|
+
|
44
|
+
# Part of testing API - you should not use this directly
|
45
|
+
attr_reader :info
|
42
46
|
|
43
47
|
# "block version" of #new()
|
44
48
|
def self.open(*args)
|
@@ -161,20 +165,36 @@ class AudioInfo
|
|
161
165
|
|
162
166
|
when 'flac'
|
163
167
|
@info = FlacInfo.new(filename)
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
@
|
168
|
+
# Unfortunately, FlacInfo doesn't allow us to fiddle inside
|
169
|
+
# their class, so we have to brute force it. Any other
|
170
|
+
# solution (e.g. creating another abstraction or getting
|
171
|
+
# methods) lands up being more messy and brittle.
|
172
|
+
@info.instance_variable_set('@tags', CaseInsensitiveHash.new(@info.tags))
|
173
|
+
|
174
|
+
get_tag = proc do |name|
|
175
|
+
if t = @info.tags[name]
|
176
|
+
t.dup.force_encoding("utf-8")
|
177
|
+
else
|
178
|
+
nil
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
@artist = get_tag.call("artist")
|
183
|
+
@album = get_tag.call("album")
|
184
|
+
@title = get_tag.call("title")
|
185
|
+
@tracknum = @info.tags["tracknumber"].to_i
|
186
|
+
@date = get_tag.call("date")
|
187
|
+
@bitrate = 0
|
169
188
|
@length = @info.streaminfo["total_samples"] / @info.streaminfo["samplerate"].to_f
|
170
|
-
|
189
|
+
if @length > 0
|
190
|
+
@bitrate = File.size(filename).to_f*8/@length/1024
|
191
|
+
end
|
171
192
|
@info.tags.each do |tagname, tagvalue|
|
172
193
|
next unless tagname =~ /^musicbrainz_(.+)$/
|
173
|
-
@musicbrainz_infos[$1] =
|
194
|
+
@musicbrainz_infos[$1] = get_tag.call(tagname)
|
174
195
|
end
|
175
196
|
@musicbrainz_infos["trmid"] = @info.tags["musicip_puid"]
|
176
197
|
#default_fill_musicbrainz_fields
|
177
|
-
|
178
198
|
else
|
179
199
|
raise(AudioInfoError, "unsupported extension '.#{@extension}'")
|
180
200
|
end
|
@@ -274,7 +294,27 @@ class AudioInfo
|
|
274
294
|
fields["Track"] = @tracknum.to_s
|
275
295
|
end
|
276
296
|
else
|
277
|
-
|
297
|
+
have_metaflac = system("which metaflac > /dev/null")
|
298
|
+
have_ffmpeg = system("which ffmpeg > /dev/null")
|
299
|
+
if have_metaflac and @info.is_a?(FlacInfo)
|
300
|
+
tags = {"ARTIST" => @artist,
|
301
|
+
"ALBUM" => @album,
|
302
|
+
"TITLE" => @title,
|
303
|
+
"TRACKNUMBER" => @tracknum}.inject([]) do |tags, (key, value)|
|
304
|
+
tags + ["--set-tag", "#{key}=#{value.to_s}"]
|
305
|
+
end
|
306
|
+
tag_with_shell_command("metaflac", "--remove-all", :src)
|
307
|
+
tag_with_shell_command("metaflac", tags, :src)
|
308
|
+
elsif have_ffmpeg
|
309
|
+
tags = {"artist" => @artist,
|
310
|
+
"album" => @album,
|
311
|
+
"title" => @title}.inject([]) do |tags, (key, value)|
|
312
|
+
tags + ["-metadata", "#{key}=#{value.to_s}"]
|
313
|
+
end
|
314
|
+
tag_with_shell_command("ffmpeg", "-y", "-i", :src, "-loglevel", "quiet", tags, :dst)
|
315
|
+
else
|
316
|
+
raise(AudioInfoError, "implement me")
|
317
|
+
end
|
278
318
|
end
|
279
319
|
|
280
320
|
end
|
@@ -362,4 +402,32 @@ class AudioInfo
|
|
362
402
|
# Return the stderr because faad prints info on that fd...
|
363
403
|
status.exitstatus.zero? ? err : ''
|
364
404
|
end
|
405
|
+
|
406
|
+
def shell_escape(s)
|
407
|
+
"'" + s.gsub(/'/) { "'\\''" } + "'"
|
408
|
+
end
|
409
|
+
|
410
|
+
def tag_with_shell_command(*command_arr)
|
411
|
+
expand_command = proc do |hash|
|
412
|
+
command_arr.collect do |token|
|
413
|
+
token.is_a?(Symbol) ? hash[token] : token
|
414
|
+
end.flatten
|
415
|
+
end
|
416
|
+
|
417
|
+
hash = {:src => @path}
|
418
|
+
if command_arr.include?(:dst)
|
419
|
+
Tempfile.open(["ruby-audioinfo", "."+@extension]) do |tf|
|
420
|
+
cmd = expand_command.call(hash.merge(:dst => tf.path))
|
421
|
+
tf.close
|
422
|
+
if system(*cmd)
|
423
|
+
FileUtils.mv(tf.path, @path)
|
424
|
+
else
|
425
|
+
raise(AudioInfoError, "error while running #{command_arr[0]}")
|
426
|
+
end
|
427
|
+
end
|
428
|
+
else
|
429
|
+
cmd = expand_command.call(hash)
|
430
|
+
system(*cmd) || raise(AudioInfoError, "error while running #{command_arr[0]}")
|
431
|
+
end
|
432
|
+
end
|
365
433
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class CaseInsensitiveHash < Hash
|
2
|
+
def initialize(hash = {})
|
3
|
+
super
|
4
|
+
hash.each do |key, value|
|
5
|
+
self[key.downcase] = value
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def [](key)
|
10
|
+
super(key.downcase)
|
11
|
+
end
|
12
|
+
|
13
|
+
def []=(key, value)
|
14
|
+
super(key.downcase, value)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative "../lib/audioinfo"
|
2
|
+
require "minitest/autorun"
|
3
|
+
|
4
|
+
require "fileutils"
|
5
|
+
require "tmpdir"
|
6
|
+
|
7
|
+
require_relative "test_helper"
|
8
|
+
|
9
|
+
class TestAudioinfo < MiniTest::Unit::TestCase
|
10
|
+
|
11
|
+
FLAC_FILE = "#{Dir.tmpdir}/ruby-audioinfo-test.flac"
|
12
|
+
|
13
|
+
def setup
|
14
|
+
FileUtils.cp(File.join(SUPPORT_DIR, "440Hz-5sec.flac"), FLAC_FILE)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_flac_whitelist
|
18
|
+
i = AudioInfo.new(FLAC_FILE)
|
19
|
+
assert_kind_of FlacInfo, i.info
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_flac_tags_wrapper
|
23
|
+
i = AudioInfo.new(FLAC_FILE)
|
24
|
+
assert_kind_of CaseInsensitiveHash, i.info.tags
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_flac_writing
|
28
|
+
title = "test with utf8éblèàqsf"
|
29
|
+
ai = AudioInfo.new(FLAC_FILE)
|
30
|
+
ai.title = title
|
31
|
+
ai.close
|
32
|
+
ai = AudioInfo.new(FLAC_FILE)
|
33
|
+
assert_equal title, ai.title
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "audioinfo"
|
2
|
+
require "minitest/autorun"
|
3
|
+
|
4
|
+
class TestCaseInsensitiveHash < MiniTest::Unit::TestCase
|
5
|
+
|
6
|
+
def test_string_access
|
7
|
+
h = CaseInsensitiveHash.new
|
8
|
+
h["foo"] = "bar"
|
9
|
+
assert_equal "bar", h["foo"]
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_symbol_access
|
13
|
+
h = CaseInsensitiveHash.new
|
14
|
+
h[:foo] = "bar"
|
15
|
+
assert_equal "bar", h[:foo]
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_case_insensitive_access
|
19
|
+
h = CaseInsensitiveHash.new
|
20
|
+
h["FOO"] = "bar"
|
21
|
+
assert_equal "bar", h["foo"]
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_copy_constructor
|
25
|
+
h = CaseInsensitiveHash.new({"FOO" => "bar"})
|
26
|
+
assert_equal "bar", h["foo"]
|
27
|
+
end
|
28
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
SUPPORT_DIR = File.expand_path("support", File.dirname(__FILE__))
|
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-audioinfo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.3.1
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Guillaume Pierronnet
|
@@ -10,102 +9,124 @@ authors:
|
|
10
9
|
autorequire:
|
11
10
|
bindir: bin
|
12
11
|
cert_chain: []
|
13
|
-
date:
|
12
|
+
date: 2013-03-26 00:00:00.000000000 Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: ruby-mp3info
|
17
|
-
requirement:
|
18
|
-
none: false
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
19
17
|
requirements:
|
20
|
-
- -
|
18
|
+
- - '>='
|
21
19
|
- !ruby/object:Gem::Version
|
22
|
-
version: 0.
|
20
|
+
version: '0.8'
|
23
21
|
type: :runtime
|
24
22
|
prerelease: false
|
25
|
-
version_requirements:
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - '>='
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0.8'
|
26
28
|
- !ruby/object:Gem::Dependency
|
27
29
|
name: ruby-ogginfo
|
28
|
-
requirement:
|
29
|
-
none: false
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
30
31
|
requirements:
|
31
|
-
- -
|
32
|
+
- - '>='
|
32
33
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.6.
|
34
|
+
version: 0.6.11
|
34
35
|
type: :runtime
|
35
36
|
prerelease: false
|
36
|
-
version_requirements:
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - '>='
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 0.6.11
|
37
42
|
- !ruby/object:Gem::Dependency
|
38
43
|
name: mp4info
|
39
|
-
requirement:
|
40
|
-
none: false
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
41
45
|
requirements:
|
42
|
-
- -
|
46
|
+
- - '>='
|
43
47
|
- !ruby/object:Gem::Version
|
44
48
|
version: 1.7.3
|
45
49
|
type: :runtime
|
46
50
|
prerelease: false
|
47
|
-
version_requirements:
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 1.7.3
|
48
56
|
- !ruby/object:Gem::Dependency
|
49
57
|
name: moumar-wmainfo-rb
|
50
|
-
requirement:
|
51
|
-
none: false
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
52
59
|
requirements:
|
53
|
-
- -
|
60
|
+
- - '>='
|
54
61
|
- !ruby/object:Gem::Version
|
55
62
|
version: '0.7'
|
56
63
|
type: :runtime
|
57
64
|
prerelease: false
|
58
|
-
version_requirements:
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0.7'
|
59
70
|
- !ruby/object:Gem::Dependency
|
60
71
|
name: flacinfo-rb
|
61
|
-
requirement:
|
62
|
-
none: false
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
63
73
|
requirements:
|
64
|
-
- -
|
74
|
+
- - '>='
|
65
75
|
- !ruby/object:Gem::Version
|
66
76
|
version: '0.4'
|
67
77
|
type: :runtime
|
68
78
|
prerelease: false
|
69
|
-
version_requirements:
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - '>='
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0.4'
|
70
84
|
- !ruby/object:Gem::Dependency
|
71
85
|
name: apetag
|
72
|
-
requirement:
|
73
|
-
none: false
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
74
87
|
requirements:
|
75
|
-
- -
|
88
|
+
- - '>='
|
76
89
|
- !ruby/object:Gem::Version
|
77
90
|
version: 1.1.4
|
78
91
|
type: :runtime
|
79
92
|
prerelease: false
|
80
|
-
version_requirements:
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - '>='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: 1.1.4
|
81
98
|
- !ruby/object:Gem::Dependency
|
82
99
|
name: rdoc
|
83
|
-
requirement:
|
84
|
-
none: false
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
85
101
|
requirements:
|
86
102
|
- - ~>
|
87
103
|
- !ruby/object:Gem::Version
|
88
104
|
version: '3.10'
|
89
105
|
type: :development
|
90
106
|
prerelease: false
|
91
|
-
version_requirements:
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ~>
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '3.10'
|
92
112
|
- !ruby/object:Gem::Dependency
|
93
113
|
name: hoe
|
94
|
-
requirement:
|
95
|
-
none: false
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
96
115
|
requirements:
|
97
116
|
- - ~>
|
98
117
|
- !ruby/object:Gem::Version
|
99
|
-
version: '3.
|
118
|
+
version: '3.5'
|
100
119
|
type: :development
|
101
120
|
prerelease: false
|
102
|
-
version_requirements:
|
103
|
-
|
104
|
-
|
105
|
-
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ~>
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '3.5'
|
126
|
+
description: |-
|
127
|
+
ruby-audioinfo glue together various audio ruby libraries and presents a unified
|
106
128
|
API to the developper. Currently, supported formats are: mp3, ogg, mpc, ape,
|
107
|
-
|
108
|
-
wma, flac, aac, mp4, m4a.'
|
129
|
+
wma, flac, aac, mp4, m4a.
|
109
130
|
email:
|
110
131
|
- guillaume.pierronnet@gmail.com
|
111
132
|
- unknown
|
@@ -123,10 +144,15 @@ files:
|
|
123
144
|
- lib/audioinfo.rb
|
124
145
|
- lib/audioinfo/album.rb
|
125
146
|
- lib/audioinfo/mpcinfo.rb
|
147
|
+
- lib/audioinfo/case_insensitive_hash.rb
|
126
148
|
- test/mpcinfo.rb
|
149
|
+
- test/test_helper.rb
|
150
|
+
- test/test_case_insensitive_hash.rb
|
151
|
+
- test/test_audioinfo.rb
|
127
152
|
- .gemtest
|
128
153
|
homepage: http://ruby-audioinfo.rubyforge.org
|
129
154
|
licenses: []
|
155
|
+
metadata: {}
|
130
156
|
post_install_message:
|
131
157
|
rdoc_options:
|
132
158
|
- --main
|
@@ -134,22 +160,23 @@ rdoc_options:
|
|
134
160
|
require_paths:
|
135
161
|
- lib
|
136
162
|
required_ruby_version: !ruby/object:Gem::Requirement
|
137
|
-
none: false
|
138
163
|
requirements:
|
139
|
-
- -
|
164
|
+
- - '>='
|
140
165
|
- !ruby/object:Gem::Version
|
141
166
|
version: '0'
|
142
167
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
143
|
-
none: false
|
144
168
|
requirements:
|
145
|
-
- -
|
169
|
+
- - '>='
|
146
170
|
- !ruby/object:Gem::Version
|
147
171
|
version: '0'
|
148
172
|
requirements: []
|
149
173
|
rubyforge_project: ruby-audioinfo
|
150
|
-
rubygems_version:
|
174
|
+
rubygems_version: 2.0.0
|
151
175
|
signing_key:
|
152
|
-
specification_version:
|
176
|
+
specification_version: 4
|
153
177
|
summary: ruby-audioinfo glue together various audio ruby libraries and presents a
|
154
178
|
unified API to the developper
|
155
|
-
test_files:
|
179
|
+
test_files:
|
180
|
+
- test/test_helper.rb
|
181
|
+
- test/test_case_insensitive_hash.rb
|
182
|
+
- test/test_audioinfo.rb
|