easytag 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d32bfe7e7828920f2801fd17d56c52362eeb9a97
4
- data.tar.gz: 2e8739c3b7ed170e5db24ab52e75fb6494d777c6
3
+ metadata.gz: 1eef251238ecbdd6cc6b83991a3aad154a2a9007
4
+ data.tar.gz: 844c9b1b74f2a9cd67127e4a8d56a79f0387de48
5
5
  SHA512:
6
- metadata.gz: fc522bd6064e15d3e08bfc13d0e0a5ff659730f7a684c4141ad3551e8dbce792bec92f9cee40a8772c64a991352d6d8be600d67b9c02fb696779c47e1485bb52
7
- data.tar.gz: 41a958d976e06dd70321632b9b080d350ed82b2069124f26092b79f732f24fb90eadc0556368b277d977116a7196b78ca6d610468130f86a2eeac1a85a016b78
6
+ metadata.gz: 0a54438c37cade246206bc4f7bf0d0f0458e7d1fb2d002f09c642aca7a8f818aa7a3e9f54ceba51bbca22cb99fd9c75a330d11fb666fcae830706fe69062f10d
7
+ data.tar.gz: 5dbbd2002796e72d4c8884950e066be03054e88eee2de85d0f91539b8b84e4bfc347136afce68f9caf288097d0259f44bfb49c282f45d927f4737ec191247d37
data/CHANGELOG.md CHANGED
@@ -1,4 +1,22 @@
1
- ##### v0.2.0 (Not yet released) #####
1
+ ##### v0.3.0 (2013-05-29) #####
2
+ * added:
3
+ - `#encoded_by`
4
+ - `#encoder_settings`
5
+ - `#group`
6
+ - `#composer`
7
+ - `#lyrics`
8
+ - `#compilation?`
9
+ - `#subtitle`
10
+ - `#bpm`
11
+ - `#lyricist`
12
+ - `#copyright`
13
+ - `#comment`
14
+
15
+ * changed:
16
+ - `#comments` now returns an array, `#comment` is the
17
+ equivalent of the old behavior
18
+
19
+ ##### v0.2.0 (2013-05-25) #####
2
20
  * added:
3
21
  - `#track_num`
4
22
  - `#disc_num`
data/easytag.gemspec CHANGED
@@ -6,7 +6,11 @@ Gem::Specification.new do |s|
6
6
  s.name = 'easytag'
7
7
  s.version = EasyTag::VERSION
8
8
  s.summary = 'A simple audio metadata tagging interface'
9
- s.description = `head -n1 README.md | ./bin/strip_md.rb`
9
+ s.description = <<-EOF
10
+ EasyTag is an abstraction layer to the TagLib audio tagging library.
11
+ It is designed to provide a simple and consistent API regardless
12
+ of file format being read.
13
+ EOF
10
14
  s.authors = ['Chris Lucas']
11
15
  s.email = ['chris@chrisjlucas.com']
12
16
  s.homepage = 'https://github.com/cjlucas/ruby-easytag'
File without changes
@@ -0,0 +1,103 @@
1
+ module EasyTag::Attributes
2
+ # for type casting
3
+ module Type
4
+ STRING = 0
5
+ INT = 1
6
+ FLOAT = 2
7
+ INT_LIST = 3
8
+ STRING_LIST = 4
9
+ BOOLEAN = 5
10
+ DATETIME = 6
11
+ end
12
+ class BaseAttribute
13
+ Utilities = EasyTag::Utilities
14
+
15
+ def initialize(args)
16
+ @name = args[:name]
17
+ @default = args[:default]
18
+ @type = args[:type] || Type::STRING
19
+ @options = args[:options] || {}
20
+ @ivar = BaseAttribute.name_to_ivar(@name)
21
+
22
+ if args[:handler].is_a?(Symbol)
23
+ @handler = method(args[:handler])
24
+ elsif args[:handler].is_a?(Proc)
25
+ @handler = args[:handler]
26
+ end
27
+
28
+ # fill default options
29
+
30
+ # Remove nil objects from array (post process)
31
+ @options[:compact] ||= false
32
+ # normalizes key (if hash) (handler)
33
+ @options[:normalize] ||= false
34
+ # cast key (if hash) to symbol (handler)
35
+ @options[:to_sym] ||= false
36
+
37
+ end
38
+
39
+ def self.can_clone?(obj)
40
+ obj.is_a?(String) || obj.is_a?(Array) || obj.is_a?(Hash)
41
+ end
42
+
43
+ def self.deep_copy(obj)
44
+ Marshal.load(Marshal.dump(obj))
45
+ end
46
+
47
+ def default
48
+ BaseAttribute.can_clone?(@default) ?
49
+ BaseAttribute.deep_copy(@default) : @default
50
+ end
51
+
52
+ def call(iface)
53
+ #puts 'entered call()'
54
+ data = @handler.call(iface)
55
+ data = type_cast(data)
56
+ post_process(data)
57
+ end
58
+
59
+ def type_cast(data)
60
+ case @type
61
+ when Type::INT
62
+ data = data.to_i
63
+ when Type::DATETIME
64
+ data = Utilities.get_datetime(data.to_s)
65
+ end
66
+
67
+ data
68
+ end
69
+
70
+ def post_process(data)
71
+ if @options[:is_flag]
72
+ data = data.to_i == 1 ? true : false
73
+ end
74
+
75
+ # fall back to default if data is nil
76
+ data = BaseAttribute.obj_or_nil(data) || default
77
+
78
+ # run obj_or_nil on each item in array
79
+ data.map! { |item| BaseAttribute.obj_or_nil(item) } if data.is_a?(Array)
80
+
81
+ if @options[:compact] && data.respond_to?(:compact!)
82
+ data.compact!
83
+ end
84
+
85
+ data
86
+ end
87
+ # avoid returing empty objects
88
+ def self.obj_or_nil(o)
89
+ if o.class == String
90
+ ret = o.empty? ? nil : o
91
+ else
92
+ o
93
+ end
94
+ end
95
+
96
+ def self.name_to_ivar(name)
97
+ name = name.to_s if name.class == Symbol
98
+ name.gsub!(/\?/, '')
99
+ name.insert(0, '@')
100
+ name.to_sym
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,382 @@
1
+ require 'taglib'
2
+
3
+ require 'easytag/image'
4
+ require 'easytag/util'
5
+ require 'easytag/attributes/base'
6
+
7
+ module EasyTag::Attributes
8
+ class MP3Attribute < BaseAttribute
9
+ attr_reader :name, :ivar
10
+
11
+ def initialize(args)
12
+ super(args)
13
+ @id3v2_frames = args[:id3v2_frames] || []
14
+ @id3v1_tag = args[:id3v1_tag] || nil
15
+
16
+ # fill default options
17
+
18
+ # ID3 stores boolean values as numeric strings
19
+ # set to true to enable type casting (post process)
20
+ @options[:is_flag] ||= false
21
+ # return entire field list instead of first item in field list
22
+ @options[:field_list] ||= false
23
+ end
24
+
25
+
26
+ def frames_for_id(id, iface)
27
+ iface.info.id3v2_tag.frame_list(id)
28
+ end
29
+
30
+ def first_frame_for_id(id, iface)
31
+ frames_for_id(id, iface).first
32
+ end
33
+
34
+ def data_from_frame(frame)
35
+ data = nil
36
+ if frame.is_a?(TagLib::ID3v2::TextIdentificationFrame)
37
+ field_list = frame.field_list
38
+ data = @options[:field_list] ? field_list : field_list.first
39
+ elsif frame.is_a?(TagLib::ID3v2::UnsynchronizedLyricsFrame)
40
+ data = frame.text
41
+ elsif frame.is_a?(TagLib::ID3v2::CommentsFrame)
42
+ data = frame.text
43
+ elsif frame.is_a?(TagLib::ID3v2::AttachedPictureFrame)
44
+ data = EasyTag::Image.new(frame.picture)
45
+ data.desc = frame.description
46
+ data.type = frame.type
47
+ data.mime_type = frame.mime_type
48
+ else
49
+ warn 'no defined frames match the given frame'
50
+ end
51
+
52
+ data
53
+ end
54
+
55
+ #
56
+ # read handlers
57
+ #
58
+
59
+ # read_all_id3
60
+ #
61
+ # gets data from each frame id given
62
+ # only falls back to the id3v1 tag if none found
63
+ def read_all_id3(iface)
64
+ frames = []
65
+ @id3v2_frames.each do |f|
66
+ frames += frames_for_id(f, iface)
67
+ end
68
+
69
+ data = []
70
+ # only check id3v1 if no id3v2 frames found
71
+ if frames.empty?
72
+ data << iface.info.id3v1_tag.send(@id3v1_tag) unless @id3v1_tag.nil?
73
+ else
74
+ frames.each { |frame| data << data_from_frame(frame) }
75
+ end
76
+
77
+ data
78
+ end
79
+
80
+ # read_first_id3
81
+ #
82
+ # Similar to read_all_id3, but optimized for reading only one frame at max
83
+ def read_first_id3(iface)
84
+ frame = nil
85
+ @id3v2_frames.each do |f|
86
+ frame = first_frame_for_id(f, iface) if frame.nil?
87
+ end
88
+
89
+ if frame.nil?
90
+ data = iface.info.id3v1_tag.send(@id3v1_tag) unless @id3v1_tag.nil?
91
+ else
92
+ data = data_from_frame(frame)
93
+ end
94
+
95
+ data
96
+ end
97
+
98
+ def read_int_pair(iface)
99
+ int_pair_str = read_first_id3(iface).to_s
100
+ EasyTag::Utilities.get_int_pair(int_pair_str)
101
+ end
102
+
103
+ def read_field_list_as_key_value(iface)
104
+ kv_hash = {}
105
+ frame_data = read_all_id3(iface)
106
+
107
+ frame_data.each do |data|
108
+ key, value = data
109
+ key = Utilities.normalize_string(key) if @options[:normalize]
110
+ key = key.to_sym if @options[:to_sym]
111
+ kv_hash[key] = value
112
+ end
113
+
114
+ kv_hash
115
+ end
116
+
117
+ def read_date(iface)
118
+ id3v1 = iface.info.id3v1_tag
119
+
120
+ v10_year = id3v1.year.to_s if id3v1.year > 0
121
+ v23_year = data_from_frame(first_frame_for_id('TYER', iface))
122
+ v23_date = data_from_frame(first_frame_for_id('TDAT', iface))
123
+ v24_date = data_from_frame(first_frame_for_id('TDRC', iface))
124
+
125
+ # check variables in order of importance
126
+ date_str = v24_date || v23_year || v10_year
127
+ # only append v23_date if date_str is currently a year
128
+ date_str << v23_date unless v23_date.nil? or date_str.length > 4
129
+ puts "MP3#date: date_str = \"#{date_str}\"" if $DEBUG
130
+
131
+ date_str
132
+ end
133
+ end
134
+ end
135
+
136
+ module EasyTag::Attributes
137
+ MP3_ATTRIB_ARGS = [
138
+ # title
139
+ {
140
+ :name => :title,
141
+ :id3v2_frames => ['TIT2'],
142
+ :id3v1_tag => :title,
143
+ :handler => :read_first_id3,
144
+ :type => Type::STRING,
145
+ },
146
+
147
+ # title_sort_order
148
+ # TSOT - (v2.4 only)
149
+ # XSOT - Musicbrainz Picard custom
150
+ {
151
+ :name => :title_sort_order,
152
+ :id3v2_frames => ['TSOT', 'XSOT'],
153
+ :handler => :read_first_id3,
154
+ },
155
+
156
+ # subtitle
157
+ {
158
+ :name => :subtitle,
159
+ :id3v2_frames => ['TIT1'],
160
+ :handler => :read_first_id3,
161
+ },
162
+
163
+ # artist
164
+ {
165
+ :name => :artist,
166
+ :id3v2_frames => ['TPE1'],
167
+ :id3v1_tag => :artist,
168
+ :handler => :read_first_id3,
169
+ },
170
+
171
+ # artist_sort_order
172
+ # TSOP - (v2.4 only)
173
+ # XSOP - Musicbrainz Picard custom
174
+ {
175
+ :name => :artist_sort_order,
176
+ :id3v2_frames => ['TSOP', 'XSOP'],
177
+ :handler => :read_first_id3,
178
+ },
179
+
180
+ # album_artist
181
+ {
182
+ :name => :album_artist,
183
+ :id3v2_frames => ['TPE2'],
184
+ :handler => :read_first_id3,
185
+ },
186
+
187
+ # album_artist_sort_order
188
+ {
189
+ :name => :album_artist_sort_order,
190
+ :handler => lambda { |iface| iface.user_info[:albumartistsort] }
191
+ },
192
+
193
+ # album
194
+ {
195
+ :name => :album,
196
+ :id3v2_frames => ['TALB'],
197
+ :id3v1_tag => :album,
198
+ :handler => :read_first_id3,
199
+ },
200
+
201
+ # compilation?
202
+ {
203
+ :name => :compilation?,
204
+ :id3v2_frames => ['TCMP'],
205
+ :default => false,
206
+ :handler => :read_first_id3,
207
+ :options => {:is_flag => true},
208
+ },
209
+
210
+ # album_sort_order
211
+ # TSOA - (v2.4 only)
212
+ # XSOA - Musicbrainz Picard custom
213
+ {
214
+ :name => :album_sort_order,
215
+ :id3v2_frames => ['TSOA', 'XSOA'],
216
+ :handler => :read_first_id3,
217
+ },
218
+
219
+ # genre
220
+ {
221
+ :name => :genre,
222
+ :id3v2_frames => ['TCON'],
223
+ :id3v1_tag => :genre,
224
+ :handler => :read_first_id3,
225
+ },
226
+
227
+ # disc_subtitle
228
+ {
229
+ :name => :disc_subtitle,
230
+ :id3v2_frames => ['TSST'],
231
+ :handler => :read_first_id3,
232
+ },
233
+
234
+ # media
235
+ {
236
+ :name => :media,
237
+ :id3v2_frames => ['TMED'],
238
+ :handler => :read_first_id3,
239
+ },
240
+
241
+ # label
242
+ {
243
+ :name => :label,
244
+ :id3v2_frames => ['TPUB'],
245
+ :handler => :read_first_id3,
246
+ },
247
+
248
+ # encoded_by
249
+ {
250
+ :name => :encoded_by,
251
+ :id3v2_frames => ['TENC'],
252
+ :handler => :read_first_id3,
253
+ },
254
+
255
+ # encoder_settings
256
+ {
257
+ :name => :encoder_settings,
258
+ :id3v2_frames => ['TSSE'],
259
+ :handler => :read_first_id3,
260
+ },
261
+
262
+ # group
263
+ {
264
+ :name => :group,
265
+ :id3v2_frames => ['TIT1'],
266
+ :handler => :read_first_id3,
267
+ },
268
+
269
+ # composer
270
+ {
271
+ :name => :composer,
272
+ :id3v2_frames => ['TCOM'],
273
+ :handler => :read_first_id3,
274
+ },
275
+
276
+ # lyrics
277
+ {
278
+ :name => :lyrics,
279
+ :id3v2_frames => ['USLT'],
280
+ :handler => :read_first_id3,
281
+ },
282
+
283
+ # lyricist
284
+ {
285
+ :name => :lyricist,
286
+ :id3v2_frames => ['TEXT'],
287
+ :handler => :read_first_id3,
288
+ },
289
+
290
+ # copyright
291
+ {
292
+ :name => :copyright,
293
+ :id3v2_frames => ['TCOP'],
294
+ :handler => :read_first_id3,
295
+ },
296
+
297
+ # bpm
298
+ {
299
+ :name => :bpm,
300
+ :id3v2_frames => ['TBPM'],
301
+ :handler => :read_first_id3,
302
+ :type => Type::INT,
303
+ },
304
+
305
+ # track_num
306
+ {
307
+ :name => :track_num,
308
+ :id3v2_frames => ['TRCK'],
309
+ :id3v1_tag => :track,
310
+ :default => [0, 0],
311
+ :handler => :read_int_pair,
312
+ :type => Type::INT_LIST, # don't know if this will ever be useful
313
+ },
314
+
315
+ # disc_num
316
+ {
317
+ :name => :disc_num,
318
+ :id3v2_frames => ['TPOS'],
319
+ :default => [0, 0],
320
+ :handler => :read_int_pair,
321
+ :type => Type::INT_LIST, # don't know if this will ever be useful
322
+ },
323
+
324
+ # original_date
325
+ # TDOR - orig release date (v2.4 only)
326
+ # TORY - orig release year (v2.3)
327
+ {
328
+ :name => :original_date,
329
+ :id3v2_frames => ['TDOR', 'TORY'],
330
+ :handler => :read_first_id3,
331
+ :type => Type::DATETIME,
332
+ },
333
+
334
+ # comments
335
+ {
336
+ :name => :comments,
337
+ :id3v2_frames => ['COMM'],
338
+ :id3v1_tag => :comment,
339
+ :handler => :read_all_id3,
340
+ :default => [],
341
+ :options => { :compact => true }
342
+ },
343
+
344
+ # comment
345
+ {
346
+ :name => :comment,
347
+ :handler => lambda { |iface| iface.comments.first }
348
+ },
349
+
350
+ # album_art
351
+ {
352
+ :name => :album_art,
353
+ :id3v2_frames => ['APIC'],
354
+ :handler => :read_all_id3,
355
+ :default => [],
356
+ },
357
+
358
+ # date
359
+ {
360
+ :name => :date,
361
+ :handler => :read_date,
362
+ :type => Type::DATETIME,
363
+ },
364
+
365
+ # year
366
+ {
367
+ :name => :year,
368
+ :handler => lambda { |iface| iface.date.nil? ? 0 : iface.date.year }
369
+ },
370
+
371
+ # user_info
372
+ {
373
+ :name => :user_info_new,
374
+ :id3v2_frames => ['TXXX'],
375
+ :handler => :read_field_list_as_key_value,
376
+ :default => {},
377
+ :options => { :normalize => true,
378
+ :to_sym => true,
379
+ :field_list => true },
380
+ },
381
+ ]
382
+ end