ruby-audioinfo 0.5.2 → 0.5.4
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|