ruby-audioinfo 0.5.2 → 0.5.4
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.
- checksums.yaml +5 -5
- data/.github/workflows/ruby.yml +53 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +10 -0
- data/.rubocop_todo.yml +116 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +76 -0
- data/History.txt +10 -2
- data/README.md +56 -0
- data/Rakefile +11 -37
- data/bin/console +15 -0
- data/codecov.yml +1 -0
- data/lib/audioinfo.rb +165 -186
- data/lib/audioinfo/album.rb +110 -111
- data/lib/audioinfo/case_insensitive_hash.rb +3 -1
- data/lib/audioinfo/mpcinfo.rb +81 -85
- data/lib/audioinfo/version.rb +5 -0
- data/ruby-audioinfo.gemspec +35 -0
- metadata +52 -85
- data/.gemtest +0 -0
- data/Manifest.txt +0 -9
- data/README.rdoc +0 -46
- data/test/mpcinfo.rb +0 -8
- data/test/test_audioinfo.rb +0 -35
- data/test/test_case_insensitive_hash.rb +0 -28
- data/test/test_helper.rb +0 -1
- data/test/test_wav.rb +0 -27
data/Rakefile
CHANGED
@@ -1,42 +1,16 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rake/testtask'
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
developer "Guillaume Pierronnet", "guillaume.pierronnet@gmail.com"
|
10
|
-
developer 'Marcello Barnaba', "unknown"
|
11
|
-
remote_rdoc_dir = ''
|
12
|
-
rdoc_locations << "rubyforge.org:/var/www/gforge-projects/ruby-audioinfo/"
|
13
|
-
|
14
|
-
self.extra_rdoc_files = FileList["*.rdoc"]
|
15
|
-
#history_file = "History.txt"
|
16
|
-
self.readme_file = "README.rdoc"
|
17
|
-
self.test_globs = ["test/test_*.rb"]
|
18
|
-
self.rsync_args = "-rv --delete"
|
19
|
-
self.license 'GPL-3.0'
|
20
|
-
|
21
|
-
extra_deps << ['ruby-mp3info', '>= 0.8']
|
22
|
-
extra_deps << ['ruby-ogginfo', '>= 0.7']
|
23
|
-
extra_deps << ['mp4info', '>= 1.7.3']
|
24
|
-
extra_deps << ['moumar-wmainfo-rb', '>= 0.7']
|
25
|
-
extra_deps << ['flacinfo-rb', '>= 0.4']
|
26
|
-
extra_deps << ['apetag', '>= 1.1.4']
|
27
|
-
extra_deps << ['wavefile', '>= 0.6.0']
|
28
|
-
#extra_dev_deps << ["rake", ">=0"]
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
7
|
+
t.libs << 'test'
|
8
|
+
t.libs << 'lib'
|
9
|
+
t.test_files = FileList['test/**/*_test.rb']
|
29
10
|
end
|
30
11
|
|
31
|
-
|
32
|
-
# vim: syntax=Ruby
|
33
|
-
require 'rubygems'
|
34
|
-
require "rake/rdoctask"
|
12
|
+
require 'rubocop/rake_task'
|
35
13
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
rd.rdoc_files.include("README.rdoc", "History.txt", "lib/**/*.rb")
|
40
|
-
rd.title = "ruby-audioinfo #{AudioInfo::VERSION}"
|
41
|
-
end
|
42
|
-
=end
|
14
|
+
RuboCop::RakeTask.new
|
15
|
+
|
16
|
+
task default: %i[test rubocop]
|
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'audioinfo'
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require 'irb'
|
15
|
+
IRB.start(__FILE__)
|
data/codecov.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
comment: false
|
data/lib/audioinfo.rb
CHANGED
@@ -1,53 +1,45 @@
|
|
1
|
-
#
|
2
|
-
require "stringio"
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
|
-
require
|
5
|
-
require "ogginfo"
|
6
|
-
require "wmainfo"
|
7
|
-
require "mp4info"
|
8
|
-
require "flacinfo"
|
9
|
-
require "apetag"
|
10
|
-
require "wavefile"
|
3
|
+
require 'stringio'
|
11
4
|
|
12
|
-
|
5
|
+
require 'mp3info'
|
6
|
+
require 'ogginfo'
|
7
|
+
require 'wmainfo'
|
8
|
+
require 'mp4info'
|
9
|
+
require 'flacinfo'
|
10
|
+
require 'apetag'
|
11
|
+
require 'wavefile'
|
13
12
|
|
14
|
-
|
15
|
-
require "audioinfo/case_insensitive_hash"
|
13
|
+
$LOAD_PATH << __dir__
|
16
14
|
|
17
|
-
|
15
|
+
require 'audioinfo/mpcinfo'
|
16
|
+
require 'audioinfo/case_insensitive_hash'
|
17
|
+
require 'audioinfo/version'
|
18
18
|
|
19
|
-
class
|
20
|
-
if RUBY_VERSION[0..2] == "1.8"
|
21
|
-
RUBY_1_8 = true
|
22
|
-
require "iconv"
|
23
|
-
else
|
24
|
-
RUBY_1_8 = false
|
25
|
-
end
|
26
|
-
|
27
|
-
MUSICBRAINZ_FIELDS = {
|
28
|
-
"trmid" => "TRM Id",
|
29
|
-
"artistid" => "Artist Id",
|
30
|
-
"albumid" => "Album Id",
|
31
|
-
"albumtype" => "Album Type",
|
32
|
-
"albumstatus" => "Album Status",
|
33
|
-
"albumartistid" => "Album Artist Id",
|
34
|
-
"sortname" => "Sort Name",
|
35
|
-
"trackid" => "Track Id"
|
36
|
-
}
|
19
|
+
class AudioInfoError < StandardError; end
|
37
20
|
|
38
|
-
|
21
|
+
class AudioInfo
|
22
|
+
MUSICBRAINZ_FIELDS = {
|
23
|
+
'trmid' => 'TRM Id',
|
24
|
+
'artistid' => 'Artist Id',
|
25
|
+
'albumid' => 'Album Id',
|
26
|
+
'albumtype' => 'Album Type',
|
27
|
+
'albumstatus' => 'Album Status',
|
28
|
+
'albumartistid' => 'Album Artist Id',
|
29
|
+
'sortname' => 'Sort Name',
|
30
|
+
'trackid' => 'Track Id'
|
31
|
+
}.freeze
|
39
32
|
|
40
|
-
|
33
|
+
SUPPORTED_EXTENSIONS = %w[mp3 ogg opus spx mpc wma mp4 aac m4a flac wav].freeze
|
41
34
|
|
42
|
-
attr_reader :path, :extension, :musicbrainz_infos, :tracknum, :bitrate, :vbr
|
43
|
-
attr_reader :artist, :album, :title, :length, :date
|
35
|
+
attr_reader :path, :extension, :musicbrainz_infos, :tracknum, :bitrate, :vbr, :artist, :album, :title, :length, :date
|
44
36
|
|
45
37
|
# Part of testing API - you should not use this directly
|
46
38
|
attr_reader :info
|
47
39
|
|
48
40
|
# "block version" of #new()
|
49
41
|
def self.open(*args)
|
50
|
-
audio_info =
|
42
|
+
audio_info = new(*args)
|
51
43
|
ret = nil
|
52
44
|
if block_given?
|
53
45
|
begin
|
@@ -63,50 +55,50 @@ class AudioInfo
|
|
63
55
|
|
64
56
|
# test whether +path+ is a valid and supported audiofile
|
65
57
|
def self.is_audio_file?(path)
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
return false
|
71
|
-
end
|
58
|
+
AudioInfo.new(path)
|
59
|
+
true
|
60
|
+
rescue AudioInfoError
|
61
|
+
false
|
72
62
|
end
|
73
63
|
|
74
64
|
# open the file with path +fn+
|
75
|
-
def initialize(filename)
|
76
|
-
raise(AudioInfoError,
|
65
|
+
def initialize(filename, extension = nil)
|
66
|
+
raise(AudioInfoError, 'path is nil') if filename.nil?
|
67
|
+
|
77
68
|
@path = filename
|
78
69
|
ext = File.extname(@path)
|
79
|
-
|
80
|
-
|
70
|
+
@extension = extension || (ext && ext[1..-1].downcase)
|
71
|
+
raise(AudioInfoError, 'cannot find extension') if @extension.empty?
|
72
|
+
|
81
73
|
@musicbrainz_infos = {}
|
82
74
|
|
83
75
|
begin
|
84
76
|
case @extension
|
85
|
-
|
77
|
+
when 'mp3'
|
86
78
|
@info = Mp3Info.new(filename)
|
87
79
|
default_tag_fill
|
88
|
-
#"TXXX"=>
|
89
|
-
#["MusicBrainz TRM Id\000",
|
90
|
-
#"MusicBrainz Artist Id\000aba64937-3334-4c65-90a1-4e6b9d4d7ada",
|
91
|
-
#"MusicBrainz Album Id\000e1a223c1-cbc2-427f-a192-5d22fefd7c4c",
|
92
|
-
#"MusicBrainz Album Type\000album",
|
93
|
-
#"MusicBrainz Album Status\000official",
|
94
|
-
#"MusicBrainz Album Artist Id\000"]
|
95
|
-
|
96
|
-
if (arr = @info.tag2[
|
80
|
+
# "TXXX"=>
|
81
|
+
# ["MusicBrainz TRM Id\000",
|
82
|
+
# "MusicBrainz Artist Id\000aba64937-3334-4c65-90a1-4e6b9d4d7ada",
|
83
|
+
# "MusicBrainz Album Id\000e1a223c1-cbc2-427f-a192-5d22fefd7c4c",
|
84
|
+
# "MusicBrainz Album Type\000album",
|
85
|
+
# "MusicBrainz Album Status\000official",
|
86
|
+
# "MusicBrainz Album Artist Id\000"]
|
87
|
+
|
88
|
+
if (arr = @info.tag2['TXXX']).is_a?(Array)
|
97
89
|
fields = MUSICBRAINZ_FIELDS.invert
|
98
90
|
arr.each do |val|
|
99
91
|
if val =~ /^MusicBrainz (.+)\000(.*)$/
|
100
|
-
|
101
|
-
|
102
|
-
|
92
|
+
short_name = fields[Regexp.last_match(1)]
|
93
|
+
@musicbrainz_infos[short_name] = Regexp.last_match(2).gsub("\xEF\xBB\xBF".force_encoding('UTF-8'), '')
|
94
|
+
end
|
103
95
|
end
|
104
96
|
end
|
105
97
|
@bitrate = @info.bitrate
|
106
98
|
i = @info.tag.tracknum
|
107
99
|
@tracknum = (i.is_a?(Array) ? i.last : i).to_i
|
108
100
|
@length = @info.length.to_i
|
109
|
-
@date = @info.tag[
|
101
|
+
@date = @info.tag['date']
|
110
102
|
@vbr = @info.vbr
|
111
103
|
@info.close
|
112
104
|
|
@@ -114,56 +106,56 @@ class AudioInfo
|
|
114
106
|
@info = OggInfo.new(filename)
|
115
107
|
default_fill_musicbrainz_fields
|
116
108
|
default_tag_fill
|
117
|
-
@bitrate = @info.bitrate/1000
|
109
|
+
@bitrate = @info.bitrate / 1000
|
118
110
|
@tracknum = @info.tag.tracknumber.to_i
|
119
111
|
@length = @info.length.to_i
|
120
|
-
@date = @info.tag[
|
112
|
+
@date = @info.tag['date']
|
121
113
|
@vbr = true
|
122
114
|
@info.close
|
123
115
|
|
124
|
-
|
116
|
+
when 'mpc'
|
125
117
|
fill_ape_tag(filename)
|
126
|
-
|
127
|
-
@bitrate = mpc_info.infos['bitrate']/1000
|
128
|
-
|
118
|
+
mpc_info = MpcInfo.new(filename)
|
119
|
+
@bitrate = mpc_info.infos['bitrate'] / 1000
|
120
|
+
@length = mpc_info.infos['length']
|
129
121
|
|
130
122
|
when 'ape'
|
131
|
-
|
123
|
+
fill_ape_tag(filename)
|
132
124
|
|
133
125
|
when 'wma'
|
134
|
-
@info = WmaInfo.new(filename, :
|
135
|
-
@artist = @info.tags[
|
136
|
-
@album = @info.tags[
|
137
|
-
@title = @info.tags[
|
138
|
-
@tracknum = @info.tags[
|
139
|
-
@date = @info.tags[
|
140
|
-
@bitrate = @info.info[
|
141
|
-
@length = @info.info[
|
126
|
+
@info = WmaInfo.new(filename, encoding: 'utf-8')
|
127
|
+
@artist = @info.tags['Author']
|
128
|
+
@album = @info.tags['AlbumTitle']
|
129
|
+
@title = @info.tags['Title']
|
130
|
+
@tracknum = @info.tags['TrackNumber'].to_i
|
131
|
+
@date = @info.tags['Year']
|
132
|
+
@bitrate = @info.info['bitrate']
|
133
|
+
@length = @info.info['playtime_seconds']
|
142
134
|
MUSICBRAINZ_FIELDS.each do |key, original_key|
|
143
135
|
@musicbrainz_infos[key] =
|
144
|
-
|
145
|
-
|
146
|
-
|
136
|
+
@info.info["MusicBrainz/#{original_key.tr(' ', '')}"] ||
|
137
|
+
@info.info["MusicBrainz/#{original_key}"]
|
138
|
+
end
|
147
139
|
|
148
|
-
|
140
|
+
when 'mp4', 'aac', 'm4a'
|
149
141
|
@extension = 'mp4'
|
150
142
|
@info = MP4Info.open(filename)
|
151
143
|
@artist = @info.ART
|
152
144
|
@album = @info.ALB
|
153
145
|
@title = @info.NAM
|
154
|
-
@tracknum = (
|
146
|
+
@tracknum = (t = @info.TRKN) ? t.first : 0
|
155
147
|
@date = @info.DAY
|
156
148
|
@bitrate = @info.BITRATE
|
157
149
|
@length = @info.SECS
|
158
150
|
mapping = MUSICBRAINZ_FIELDS.invert
|
159
151
|
|
160
152
|
faad_info(filename).match(/^MusicBrainz (.+)$/) do
|
161
|
-
name, value =
|
153
|
+
name, value = Regexp.last_match(1).split(/: /, 2)
|
162
154
|
key = mapping[name]
|
163
155
|
@musicbrainz_infos[key] = value
|
164
156
|
end
|
165
157
|
|
166
|
-
|
158
|
+
when 'flac'
|
167
159
|
@info = FlacInfo.new(filename)
|
168
160
|
# Unfortunately, FlacInfo doesn't allow us to fiddle inside
|
169
161
|
# their class, so we have to brute force it. Any other
|
@@ -173,53 +165,47 @@ class AudioInfo
|
|
173
165
|
|
174
166
|
get_tag = proc do |name|
|
175
167
|
if t = @info.tags[name]
|
176
|
-
t.dup.force_encoding(
|
177
|
-
else
|
178
|
-
nil
|
168
|
+
t.dup.force_encoding('utf-8')
|
179
169
|
end
|
180
170
|
end
|
181
171
|
|
182
|
-
@artist = get_tag.call(
|
183
|
-
@album = get_tag.call(
|
184
|
-
@title = get_tag.call(
|
185
|
-
@tracknum = @info.tags[
|
186
|
-
@date = get_tag.call(
|
172
|
+
@artist = get_tag.call('artist')
|
173
|
+
@album = get_tag.call('album')
|
174
|
+
@title = get_tag.call('title')
|
175
|
+
@tracknum = @info.tags['tracknumber'].to_i
|
176
|
+
@date = get_tag.call('date')
|
187
177
|
@bitrate = 0
|
188
|
-
@length = @info.streaminfo[
|
189
|
-
|
190
|
-
|
191
|
-
end
|
192
|
-
@info.tags.each do |tagname, tagvalue|
|
178
|
+
@length = @info.streaminfo['total_samples'] / @info.streaminfo['samplerate'].to_f
|
179
|
+
@bitrate = File.size(filename).to_f * 8 / @length / 1024 if @length.positive?
|
180
|
+
@info.tags.each do |tagname, _tagvalue|
|
193
181
|
next unless tagname =~ /^musicbrainz_(.+)$/
|
194
|
-
|
182
|
+
|
183
|
+
@musicbrainz_infos[Regexp.last_match(1)] = get_tag.call(tagname)
|
195
184
|
end
|
196
|
-
@musicbrainz_infos[
|
197
|
-
|
185
|
+
@musicbrainz_infos['trmid'] = @info.tags['musicip_puid']
|
186
|
+
# default_fill_musicbrainz_fields
|
198
187
|
|
199
188
|
when 'wav'
|
200
189
|
@info = WaveFile::Reader.info(filename)
|
201
|
-
@length = @info.duration.hours * 3600 + @info.duration.minutes * 60 + @info.duration.seconds +
|
190
|
+
@length = @info.duration.hours * 3600 + @info.duration.minutes * 60 + @info.duration.seconds +
|
191
|
+
@info.duration.milliseconds * 0.001
|
202
192
|
@bitrate = File.size(filename) * 8 / @length / 1024
|
203
193
|
|
204
194
|
else
|
205
195
|
raise(AudioInfoError, "unsupported extension '.#{@extension}'")
|
206
196
|
end
|
207
197
|
|
208
|
-
if @tracknum
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
"bitrate" => @bitrate,
|
220
|
-
}
|
221
|
-
|
222
|
-
rescue Exception, Mp3InfoError, OggInfoError, ApeTagError => e
|
198
|
+
@tracknum = nil if @tracknum&.zero?
|
199
|
+
|
200
|
+
@musicbrainz_infos.delete_if { |_k, v| v.nil? }
|
201
|
+
@hash = { 'artist' => @artist,
|
202
|
+
'album' => @album,
|
203
|
+
'title' => @title,
|
204
|
+
'tracknum' => @tracknum,
|
205
|
+
'date' => @date,
|
206
|
+
'length' => @length,
|
207
|
+
'bitrate' => @bitrate }
|
208
|
+
rescue StandardError, Mp3InfoError, OggInfoError, ApeTagError => e
|
223
209
|
raise AudioInfoError, e.to_s, e.backtrace
|
224
210
|
end
|
225
211
|
|
@@ -287,113 +273,106 @@ class AudioInfo
|
|
287
273
|
info.tag.album = @album
|
288
274
|
info.tag.tracknum = @tracknum
|
289
275
|
if @picture
|
290
|
-
|
291
|
-
|
276
|
+
info.tag2.remove_pictures
|
277
|
+
info.tag2.add_picture(File.binread(@picture))
|
292
278
|
end
|
293
279
|
end
|
294
|
-
|
295
|
-
|
296
|
-
{
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
end
|
302
|
-
if @picture
|
303
|
-
ogg.picture = @picture
|
280
|
+
when OggInfo
|
281
|
+
OggInfo.open(@path) do |ogg|
|
282
|
+
{ 'artist' => @artist,
|
283
|
+
'album' => @album,
|
284
|
+
'title' => @title,
|
285
|
+
'tracknumber' => @tracknum }.each do |k, v|
|
286
|
+
ogg.tag[k] = v.to_s
|
304
287
|
end
|
288
|
+
ogg.picture = @picture if @picture
|
305
289
|
end
|
306
290
|
|
307
291
|
when ApeTag
|
308
292
|
ape = ApeTag.new(@path)
|
309
293
|
ape.update do |fields|
|
310
|
-
fields[
|
311
|
-
fields[
|
312
|
-
fields[
|
313
|
-
fields[
|
294
|
+
fields['Artist'] = @artist
|
295
|
+
fields['Album'] = @album
|
296
|
+
fields['Title'] = @title
|
297
|
+
fields['Track'] = @tracknum.to_s
|
314
298
|
end
|
315
|
-
|
316
|
-
have_metaflac = system(
|
317
|
-
have_ffmpeg = system(
|
318
|
-
if have_metaflac
|
319
|
-
tags = {
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
tags + [
|
299
|
+
else
|
300
|
+
have_metaflac = system('which metaflac > /dev/null')
|
301
|
+
have_ffmpeg = system('which ffmpeg > /dev/null')
|
302
|
+
if have_metaflac && @info.is_a?(FlacInfo)
|
303
|
+
tags = { 'ARTIST' => @artist,
|
304
|
+
'ALBUM' => @album,
|
305
|
+
'TITLE' => @title,
|
306
|
+
'TRACKNUMBER' => @tracknum }.inject([]) do |tags, (key, value)|
|
307
|
+
tags + ['--set-tag', "#{key}=#{value}"]
|
324
308
|
end
|
325
|
-
tag_with_shell_command(
|
326
|
-
tag_with_shell_command(
|
309
|
+
tag_with_shell_command('metaflac', '--remove-all', :src)
|
310
|
+
tag_with_shell_command('metaflac', tags, :src)
|
327
311
|
elsif have_ffmpeg
|
328
|
-
tags = {
|
329
|
-
|
330
|
-
|
331
|
-
tags + [
|
312
|
+
tags = { 'artist' => @artist,
|
313
|
+
'album' => @album,
|
314
|
+
'title' => @title }.inject([]) do |tags, (key, value)|
|
315
|
+
tags + ['-metadata', "#{key}=#{value}"]
|
332
316
|
end
|
333
|
-
tag_with_shell_command(
|
317
|
+
tag_with_shell_command('ffmpeg', '-y', '-i', :src, '-loglevel', 'quiet', tags, :dst)
|
334
318
|
else
|
335
|
-
raise(AudioInfoError,
|
319
|
+
raise(AudioInfoError, 'implement me')
|
336
320
|
end
|
337
321
|
end
|
338
322
|
end
|
339
323
|
@needs_commit
|
340
324
|
end
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
"musicbrainz_albumartistid"=>"89ad4ac3-39f7-470e-963a-56509c546377"}>
|
356
|
-
=end
|
325
|
+
# {"musicbrainz_albumstatus"=>"official",
|
326
|
+
# "artist"=>"Jill Scott",
|
327
|
+
# "replaygain_track_gain"=>"-3.29 dB",
|
328
|
+
# "tracknumber"=>"1",
|
329
|
+
# "title"=>"A long walk (A touch of Jazz Mix)..Jazzanova Love Beats...",
|
330
|
+
# "musicbrainz_sortname"=>"Scott, Jill",
|
331
|
+
# "musicbrainz_artistid"=>"b1fb6a18-1626-4011-80fb-eaf83dfebcb6",
|
332
|
+
# "musicbrainz_albumid"=>"cb2ad8c7-4a02-4e46-ae9a-c7c2463c7235",
|
333
|
+
# "replaygain_track_peak"=>"0.82040048",
|
334
|
+
# "musicbrainz_albumtype"=>"compilation",
|
335
|
+
# "album"=>"...Mixing (Jazzanova)",
|
336
|
+
# "musicbrainz_trmid"=>"1ecec0a6-c7c3-4179-abea-ef12dabc7cbd",
|
337
|
+
# "musicbrainz_trackid"=>"0a368e63-dddf-441f-849c-ca23f9cb2d49",
|
338
|
+
# "musicbrainz_albumartistid"=>"89ad4ac3-39f7-470e-963a-56509c546377"}>
|
357
339
|
|
358
340
|
# check if the file is correctly tagged by MusicBrainz
|
359
341
|
def mb_tagged?
|
360
|
-
|
342
|
+
!@musicbrainz_infos.empty?
|
361
343
|
end
|
362
344
|
|
363
345
|
private
|
364
346
|
|
365
347
|
def sanitize(input)
|
366
348
|
s = input.is_a?(Array) ? input.first : input
|
367
|
-
s.
|
349
|
+
s.delete("\000")
|
368
350
|
end
|
369
351
|
|
370
352
|
def default_fill_musicbrainz_fields(tags = @info.tag)
|
371
|
-
MUSICBRAINZ_FIELDS.
|
353
|
+
MUSICBRAINZ_FIELDS.each_key do |field|
|
372
354
|
val = tags["musicbrainz_#{field}"]
|
373
355
|
@musicbrainz_infos[field] = val if val
|
374
356
|
end
|
375
357
|
end
|
376
358
|
|
377
359
|
def default_tag_fill(tags = @info.tag)
|
378
|
-
%w
|
379
|
-
instance_variable_set(
|
360
|
+
%w[artist album title].each do |v|
|
361
|
+
instance_variable_set("@#{v}".to_sym, sanitize(tags[v] || ''))
|
380
362
|
end
|
381
363
|
end
|
382
364
|
|
383
365
|
def fill_ape_tag(filename)
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
hash[k.downcase] = v ? v.first : nil
|
388
|
-
hash
|
389
|
-
end
|
390
|
-
default_fill_musicbrainz_fields(tags)
|
391
|
-
default_tag_fill(tags)
|
392
|
-
|
393
|
-
@date = tags["year"]
|
394
|
-
@tracknum = tags['track'].to_i
|
395
|
-
rescue ApeTagError
|
366
|
+
@info = ApeTag.new(filename)
|
367
|
+
tags = @info.fields.each_with_object({}) do |(k, v), hash|
|
368
|
+
hash[k.downcase] = v ? v.first : nil
|
396
369
|
end
|
370
|
+
default_fill_musicbrainz_fields(tags)
|
371
|
+
default_tag_fill(tags)
|
372
|
+
|
373
|
+
@date = tags['year']
|
374
|
+
@tracknum = tags['track'].to_i
|
375
|
+
rescue ApeTagError
|
397
376
|
end
|
398
377
|
|
399
378
|
def faad_info(file)
|
@@ -403,8 +382,8 @@ class AudioInfo
|
|
403
382
|
fork do
|
404
383
|
stdout.close
|
405
384
|
stderr.close
|
406
|
-
|
407
|
-
|
385
|
+
$stdout.reopen(stdout_w)
|
386
|
+
$stderr.reopen(stderr_w)
|
408
387
|
exec 'faad', '-i', file
|
409
388
|
end
|
410
389
|
|
@@ -422,7 +401,7 @@ class AudioInfo
|
|
422
401
|
end
|
423
402
|
|
424
403
|
def shell_escape(s)
|
425
|
-
"'
|
404
|
+
"'#{s.gsub(/'/) { "'\\''" }}'"
|
426
405
|
end
|
427
406
|
|
428
407
|
def tag_with_shell_command(*command_arr)
|
@@ -432,10 +411,10 @@ class AudioInfo
|
|
432
411
|
end.flatten
|
433
412
|
end
|
434
413
|
|
435
|
-
hash = {:
|
414
|
+
hash = { src: @path }
|
436
415
|
if command_arr.include?(:dst)
|
437
|
-
Tempfile.open([
|
438
|
-
cmd = expand_command.call(hash.merge(:
|
416
|
+
Tempfile.open(['ruby-audioinfo', ".#{@extension}"]) do |tf|
|
417
|
+
cmd = expand_command.call(hash.merge(dst: tf.path))
|
439
418
|
tf.close
|
440
419
|
if system(*cmd)
|
441
420
|
FileUtils.mv(tf.path, @path)
|