easytag 0.3.1 → 0.4.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: d4c3f241efadea1f57ee59da86e825e2ab3e16f1
4
- data.tar.gz: a14c85a009253c9f8b0fd468107a9e4cc0f39cee
3
+ metadata.gz: 00e00f1b32f68a4b82926812d67662a241f3ab90
4
+ data.tar.gz: 80062af54050c116c899d079df4ad98c0db23a70
5
5
  SHA512:
6
- metadata.gz: 70ac3fa28f1bcef558a017bce6e58d2d09028fe38f24677873cbc178720e298e49a228d4b2335e9720baeb3638e70b937669999237b9f6e80ef7da5e62b2aa4f
7
- data.tar.gz: 53fe63add857a0bed84914337587486a24c22fc27c1af50cc0db3a45cc0b6849b35f447e035ca7bbee1fbc5a349069f73c980bb4472e5302286390b54c208056
6
+ metadata.gz: 18effe5cc310fb3bfc02757404f82fa6fdc84848c23c720e6c020bea7157e948c8a27e0a18495e233180a3b4af4dcd9c8acd7ef02886ab7d0d29ae83e6f2428c
7
+ data.tar.gz: 701971062dfe40d066cc4ad1a61c5bbc906ea05c9f481059a55aa1fcecf6a79fee06cc4d194cbdababd9547a80cdbe89c025c2991a21bcc4270ef9aaafc2fcde
@@ -1,3 +1,36 @@
1
+ ##### v0.4.0 (2013-06-07) #####
2
+ * added: general attributes
3
+ - `#asin`
4
+ - `#conductor`
5
+ - `#remixer`
6
+ - `#mood`
7
+ * added: musicbrainz attributes
8
+ - `#musicbrainz_track_id`
9
+ - `#musicbrainz_album_id`
10
+ - `#musicbrainz_album_status`
11
+ - `#musicbrainz_album_type`
12
+ - `#musicbrainz_album_release_country`
13
+ - `#musicbrainz_artist_id`
14
+ - `#musicbrainz_album_artist_id`
15
+ - `#musicbrainz_release_group_id`
16
+ * added: audio property attributes
17
+ - `#length` (alias: `#duration`)
18
+ - `#bitrate`
19
+ - `#sample_rate`
20
+ - `#channels`
21
+ - `MP3#layer`
22
+ - `MP3#copyrighted?`
23
+ - `MP3#original?`
24
+ - `MP3#protection_enabled?`
25
+ - `MP4#bits_per_sample`
26
+ * added: support for attribute aliases
27
+ * changed: attributes that return `String` now default to an empty string
28
+ instead of `nil`
29
+ * changed: unsupported attributes now return a default value instead of always
30
+ `nil` (ex: `MP3#apple_id`)
31
+ * fixed: `#user_info` stores an array of values if item has multiple value
32
+ * fixed: improvements to `#date` (issues #1 and #2)
33
+
1
34
  ##### v0.3.1 (2013-05-31) #####
2
35
  * fixed: `MP3#subtitle` now points to correct ID3 frame
3
36
  * fixed: restored `MP3#user_info`
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- EasyTag is an abstraction layer to the [TagLib](http://taglib.github.io/) audio tagging library. It is designed to provide a simple and consistent API regardless of file format being read.
1
+ EasyTag is an abstract interface to the [TagLib](http://taglib.github.io/) audio tagging library. It is designed to provide a simple and consistent API regardless of file format being read.
2
2
 
3
3
  A quick reference to which attributes are currently supported can be found [here](https://github.com/cjlucas/ruby-easytag/wiki/Currently-Supported-Attributes).
4
4
 
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
7
7
  s.version = EasyTag::VERSION
8
8
  s.summary = 'A simple audio metadata tagging interface'
9
9
  s.description = <<-EOF
10
- EasyTag is an abstraction layer to the TagLib audio tagging library.
10
+ EasyTag is an abstract interface to the TagLib audio tagging library.
11
11
  It is designed to provide a simple and consistent API regardless
12
12
  of file format being read.
13
13
  EOF
@@ -8,16 +8,21 @@ module EasyTag::Attributes
8
8
  STRING_LIST = 4
9
9
  BOOLEAN = 5
10
10
  DATETIME = 6
11
+ LIST = 7
11
12
  end
12
13
  class BaseAttribute
13
14
  Utilities = EasyTag::Utilities
15
+
16
+ attr_reader :name, :aliases, :ivar
14
17
 
15
18
  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)
19
+ @name = args[:name]
20
+ @type = args[:type]
21
+ @default = args[:default] || self.class.default_for_type(@type)
22
+ @options = args[:options] || {}
23
+ @handler_opts = args[:handler_opts] || {}
24
+ @aliases = args[:aliases] || []
25
+ @ivar = BaseAttribute.name_to_ivar(@name)
21
26
 
22
27
  if args[:handler].is_a?(Symbol)
23
28
  @handler = method(args[:handler])
@@ -28,11 +33,13 @@ module EasyTag::Attributes
28
33
  # fill default options
29
34
 
30
35
  # 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
+ @options[:compact] ||= false
37
+ # Delete empty objects in array (post process)
38
+ @options[:delete_empty] ||= false
39
+ # normalizes key (if hash) (handler or post process)
40
+ @options[:normalize] ||= false
41
+ # cast key (if hash) to symbol (handler or post process)
42
+ @options[:to_sym] ||= false
36
43
 
37
44
  end
38
45
 
@@ -44,13 +51,29 @@ module EasyTag::Attributes
44
51
  Marshal.load(Marshal.dump(obj))
45
52
  end
46
53
 
54
+ def self.default_for_type(type)
55
+ case type
56
+ when Type::STRING
57
+ ''
58
+ when Type::DATETIME
59
+ nil
60
+ when Type::INT
61
+ 0
62
+ when Type::INT_LIST
63
+ [0, 0] # TODO: don't assume an INT_LIST is always an int pair
64
+ when Type::BOOLEAN
65
+ false
66
+ when Type::LIST
67
+ []
68
+ end
69
+ end
70
+
47
71
  def default
48
72
  BaseAttribute.can_clone?(@default) ?
49
73
  BaseAttribute.deep_copy(@default) : @default
50
74
  end
51
75
 
52
76
  def call(iface)
53
- #puts 'entered call()'
54
77
  data = @handler.call(iface)
55
78
  data = type_cast(data)
56
79
  post_process(data)
@@ -62,6 +85,8 @@ module EasyTag::Attributes
62
85
  data = data.to_i
63
86
  when Type::DATETIME
64
87
  data = Utilities.get_datetime(data.to_s)
88
+ when Type::LIST
89
+ data = Array(data)
65
90
  end
66
91
 
67
92
  data
@@ -73,31 +98,46 @@ module EasyTag::Attributes
73
98
  end
74
99
 
75
100
  # fall back to default if data is nil
76
- data = BaseAttribute.obj_or_nil(data) || default
101
+ data ||= default
102
+
103
+ # REVIEW: the compact option may not be needed anymore
104
+ # since we've done away with casting empty strings to nil
105
+ data.compact! if @options[:compact] && data.respond_to?(:compact!)
106
+
107
+ if @options[:delete_empty]
108
+ data.select! { |item| !item.empty? if item.respond_to?(:empty?) }
109
+ end
77
110
 
78
- # run obj_or_nil on each item in array
79
- data.map! { |item| BaseAttribute.obj_or_nil(item) } if data.is_a?(Array)
111
+ data = Utilities.normalize_object(data) if @options[:normalize]
80
112
 
81
- if @options[:compact] && data.respond_to?(:compact!)
82
- data.compact!
113
+ # TODO: roll this out to a method that supports more than just array
114
+ if @options[:to_sym] && data.is_a?(Array)
115
+ data.map! { |item| item.to_sym if item.respond_to?(:to_sym) }
83
116
  end
84
117
 
85
118
  data
86
119
  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
120
+
121
+ def self.name_to_ivar(name)
122
+ name.to_s.gsub(/\?/, '').insert(0, '@').to_sym
94
123
  end
95
124
 
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
125
+ # read handlers
126
+
127
+ def read_default(iface)
128
+ default
129
+ end
130
+
131
+ def read_audio_property(iface)
132
+ key = @handler_opts[:key]
133
+ warn "@handler_opts[:key] doesn't exist" if key.nil?
134
+ iface.info.audio_properties.send(key)
135
+ end
136
+
137
+ def user_info_lookup(iface)
138
+ key = @handler_opts[:key]
139
+ warn "@handler_opts[:key] doesn't exist" if key.nil?
140
+ iface.user_info_normalized[key]
101
141
  end
102
142
  end
103
143
  end
@@ -105,10 +105,12 @@ module EasyTag::Attributes
105
105
  frame_data = read_all_id3(iface)
106
106
 
107
107
  frame_data.each do |data|
108
- key, value = data
108
+ key = data[0]
109
+ values = data[1..-1]
110
+
109
111
  key = Utilities.normalize_string(key) if @options[:normalize]
110
112
  key = key.to_sym if @options[:to_sym]
111
- kv_hash[key] = value
113
+ kv_hash[key] = values.count > 1 ? values : values.first
112
114
  end
113
115
 
114
116
  kv_hash
@@ -130,6 +132,20 @@ module EasyTag::Attributes
130
132
 
131
133
  date_str
132
134
  end
135
+
136
+ def read_ufid(iface)
137
+ frames = iface.info.id3v2_tag.frame_list('UFID')
138
+ ufid = nil
139
+
140
+ frames.each do |frame|
141
+ if @handler_opts[:owner].eql?(frame.owner)
142
+ ufid = frame.identifier
143
+ break
144
+ end
145
+ end
146
+
147
+ ufid
148
+ end
133
149
  end
134
150
  end
135
151
 
@@ -151,6 +167,7 @@ module EasyTag::Attributes
151
167
  :name => :title_sort_order,
152
168
  :id3v2_frames => ['TSOT', 'XSOT'],
153
169
  :handler => :read_first_id3,
170
+ :type => Type::STRING,
154
171
  },
155
172
 
156
173
  # subtitle
@@ -158,6 +175,7 @@ module EasyTag::Attributes
158
175
  :name => :subtitle,
159
176
  :id3v2_frames => ['TIT3'],
160
177
  :handler => :read_first_id3,
178
+ :type => Type::STRING,
161
179
  },
162
180
 
163
181
  # artist
@@ -166,6 +184,7 @@ module EasyTag::Attributes
166
184
  :id3v2_frames => ['TPE1'],
167
185
  :id3v1_tag => :artist,
168
186
  :handler => :read_first_id3,
187
+ :type => Type::STRING,
169
188
  },
170
189
 
171
190
  # artist_sort_order
@@ -175,6 +194,7 @@ module EasyTag::Attributes
175
194
  :name => :artist_sort_order,
176
195
  :id3v2_frames => ['TSOP', 'XSOP'],
177
196
  :handler => :read_first_id3,
197
+ :type => Type::STRING,
178
198
  },
179
199
 
180
200
  # album_artist
@@ -182,12 +202,15 @@ module EasyTag::Attributes
182
202
  :name => :album_artist,
183
203
  :id3v2_frames => ['TPE2'],
184
204
  :handler => :read_first_id3,
205
+ :type => Type::STRING,
185
206
  },
186
207
 
187
208
  # album_artist_sort_order
188
209
  {
189
210
  :name => :album_artist_sort_order,
190
- :handler => lambda { |iface| iface.user_info[:albumartistsort] }
211
+ :handler => :user_info_lookup,
212
+ :handler_opts => {:key => :albumartistsort},
213
+ :type => Type::STRING,
191
214
  },
192
215
 
193
216
  # album
@@ -196,14 +219,16 @@ module EasyTag::Attributes
196
219
  :id3v2_frames => ['TALB'],
197
220
  :id3v1_tag => :album,
198
221
  :handler => :read_first_id3,
222
+ :type => Type::STRING,
199
223
  },
200
224
 
201
225
  # compilation?
202
226
  {
203
227
  :name => :compilation?,
204
228
  :id3v2_frames => ['TCMP'],
205
- :default => false,
206
229
  :handler => :read_first_id3,
230
+ :type => Type::BOOLEAN,
231
+ # TODO: remove is_flag option, determine boolean value implicitly
207
232
  :options => {:is_flag => true},
208
233
  },
209
234
 
@@ -214,6 +239,7 @@ module EasyTag::Attributes
214
239
  :name => :album_sort_order,
215
240
  :id3v2_frames => ['TSOA', 'XSOA'],
216
241
  :handler => :read_first_id3,
242
+ :type => Type::STRING,
217
243
  },
218
244
 
219
245
  # genre
@@ -222,6 +248,7 @@ module EasyTag::Attributes
222
248
  :id3v2_frames => ['TCON'],
223
249
  :id3v1_tag => :genre,
224
250
  :handler => :read_first_id3,
251
+ :type => Type::STRING,
225
252
  },
226
253
 
227
254
  # disc_subtitle
@@ -229,6 +256,7 @@ module EasyTag::Attributes
229
256
  :name => :disc_subtitle,
230
257
  :id3v2_frames => ['TSST'],
231
258
  :handler => :read_first_id3,
259
+ :type => Type::STRING,
232
260
  },
233
261
 
234
262
  # media
@@ -236,6 +264,7 @@ module EasyTag::Attributes
236
264
  :name => :media,
237
265
  :id3v2_frames => ['TMED'],
238
266
  :handler => :read_first_id3,
267
+ :type => Type::STRING,
239
268
  },
240
269
 
241
270
  # label
@@ -243,6 +272,7 @@ module EasyTag::Attributes
243
272
  :name => :label,
244
273
  :id3v2_frames => ['TPUB'],
245
274
  :handler => :read_first_id3,
275
+ :type => Type::STRING,
246
276
  },
247
277
 
248
278
  # encoded_by
@@ -250,6 +280,7 @@ module EasyTag::Attributes
250
280
  :name => :encoded_by,
251
281
  :id3v2_frames => ['TENC'],
252
282
  :handler => :read_first_id3,
283
+ :type => Type::STRING,
253
284
  },
254
285
 
255
286
  # encoder_settings
@@ -257,6 +288,7 @@ module EasyTag::Attributes
257
288
  :name => :encoder_settings,
258
289
  :id3v2_frames => ['TSSE'],
259
290
  :handler => :read_first_id3,
291
+ :type => Type::STRING,
260
292
  },
261
293
 
262
294
  # group
@@ -264,6 +296,7 @@ module EasyTag::Attributes
264
296
  :name => :group,
265
297
  :id3v2_frames => ['TIT1'],
266
298
  :handler => :read_first_id3,
299
+ :type => Type::STRING,
267
300
  },
268
301
 
269
302
  # composer
@@ -271,6 +304,23 @@ module EasyTag::Attributes
271
304
  :name => :composer,
272
305
  :id3v2_frames => ['TCOM'],
273
306
  :handler => :read_first_id3,
307
+ :type => Type::STRING,
308
+ },
309
+
310
+ # conductor
311
+ {
312
+ :name => :conductor,
313
+ :id3v2_frames => ['TPE3'],
314
+ :handler => :read_first_id3,
315
+ :type => Type::STRING,
316
+ },
317
+
318
+ # remixer
319
+ {
320
+ :name => :remixer,
321
+ :id3v2_frames => ['TPE4'],
322
+ :handler => :read_first_id3,
323
+ :type => Type::STRING,
274
324
  },
275
325
 
276
326
  # lyrics
@@ -278,6 +328,7 @@ module EasyTag::Attributes
278
328
  :name => :lyrics,
279
329
  :id3v2_frames => ['USLT'],
280
330
  :handler => :read_first_id3,
331
+ :type => Type::STRING,
281
332
  },
282
333
 
283
334
  # lyricist
@@ -285,6 +336,7 @@ module EasyTag::Attributes
285
336
  :name => :lyricist,
286
337
  :id3v2_frames => ['TEXT'],
287
338
  :handler => :read_first_id3,
339
+ :type => Type::STRING,
288
340
  },
289
341
 
290
342
  # copyright
@@ -292,6 +344,7 @@ module EasyTag::Attributes
292
344
  :name => :copyright,
293
345
  :id3v2_frames => ['TCOP'],
294
346
  :handler => :read_first_id3,
347
+ :type => Type::STRING,
295
348
  },
296
349
 
297
350
  # bpm
@@ -302,6 +355,14 @@ module EasyTag::Attributes
302
355
  :type => Type::INT,
303
356
  },
304
357
 
358
+ # mood
359
+ {
360
+ :name => :mood,
361
+ :id3v2_frames => ['TMOO'],
362
+ :handler => :read_first_id3,
363
+ :type => Type::STRING,
364
+ },
365
+
305
366
  # track_num
306
367
  {
307
368
  :name => :track_num,
@@ -338,13 +399,14 @@ module EasyTag::Attributes
338
399
  :id3v1_tag => :comment,
339
400
  :handler => :read_all_id3,
340
401
  :default => [],
341
- :options => { :compact => true }
402
+ :options => { :compact => true, :delete_empty => true }
342
403
  },
343
404
 
344
405
  # comment
345
406
  {
346
407
  :name => :comment,
347
- :handler => lambda { |iface| iface.comments.first }
408
+ :handler => lambda { |iface| iface.comments.first },
409
+ :type => Type::STRING,
348
410
  },
349
411
 
350
412
  # album_art
@@ -368,15 +430,177 @@ module EasyTag::Attributes
368
430
  :handler => lambda { |iface| iface.date.nil? ? 0 : iface.date.year }
369
431
  },
370
432
 
433
+ # apple_id
434
+ {
435
+ :name => :apple_id,
436
+ :handler => :read_default,
437
+ :type => Type::STRING,
438
+ },
439
+
371
440
  # user_info
372
441
  {
373
442
  :name => :user_info,
374
443
  :id3v2_frames => ['TXXX'],
375
444
  :handler => :read_field_list_as_key_value,
376
445
  :default => {},
377
- :options => { :normalize => true,
446
+ :options => {:field_list => true},
447
+ },
448
+
449
+ # user_info_normalized
450
+ {
451
+ :name => :user_info_normalized,
452
+ :id3v2_frames => ['TXXX'],
453
+ :handler => :read_field_list_as_key_value,
454
+ :default => {},
455
+ :options => {:normalize => true,
378
456
  :to_sym => true,
379
457
  :field_list => true },
380
458
  },
459
+
460
+ # asin
461
+ {
462
+ :name => :asin,
463
+ :handler => :user_info_lookup,
464
+ :handler_opts => {:key => :asin},
465
+ :type => Type::STRING,
466
+ },
467
+
468
+ #
469
+ # MusicBrainz Attributes
470
+ #
471
+
472
+ # musicbrainz_track_id
473
+ {
474
+ :name => :musicbrainz_track_id,
475
+ :handler => :read_ufid,
476
+ :handler_opts => {:owner => 'http://musicbrainz.org'},
477
+ :type => Type::STRING,
478
+ },
479
+
480
+ # musicbrainz_album_artist_id
481
+ {
482
+ :name => :musicbrainz_album_artist_id,
483
+ :handler => :user_info_lookup,
484
+ :handler_opts => {:key => :musicbrainz_album_artist_id},
485
+ :type => Type::STRING,
486
+ },
487
+
488
+ # musicbrainz_artist_id
489
+ {
490
+ :name => :musicbrainz_artist_id,
491
+ :handler => :user_info_lookup,
492
+ :handler_opts => {:key => :musicbrainz_artist_id},
493
+ :type => Type::LIST,
494
+ },
495
+
496
+ # musicbrainz_album_id
497
+ {
498
+ :name => :musicbrainz_album_id,
499
+ :handler => :user_info_lookup,
500
+ :handler_opts => {:key => :musicbrainz_album_id},
501
+ :type => Type::STRING,
502
+ },
503
+
504
+ # musicbrainz_album_status
505
+ {
506
+ :name => :musicbrainz_album_status,
507
+ :handler => :user_info_lookup,
508
+ :handler_opts => {:key => :musicbrainz_album_status},
509
+ :type => Type::STRING,
510
+ },
511
+
512
+ # musicbrainz_album_type
513
+ {
514
+ :name => :musicbrainz_album_type,
515
+ :handler => :user_info_lookup,
516
+ :handler_opts => {:key => :musicbrainz_album_type},
517
+ :type => Type::LIST,
518
+ },
519
+
520
+
521
+ # musicbrainz_release_group_id
522
+ {
523
+ :name => :musicbrainz_release_group_id,
524
+ :handler => :user_info_lookup,
525
+ :handler_opts => {:key => :musicbrainz_release_group_id},
526
+ :type => Type::STRING,
527
+ },
528
+
529
+ # musicbrainz_album_release_country
530
+ {
531
+ :name => :musicbrainz_album_release_country,
532
+ :handler => :user_info_lookup,
533
+ :handler_opts => {:key => :musicbrainz_album_release_country},
534
+ :type => Type::STRING,
535
+ },
536
+
537
+ #
538
+ # Audio Properties
539
+ #
540
+
541
+ # length
542
+ {
543
+ :name => :length,
544
+ :aliases => [:duration],
545
+ :handler => :read_audio_property,
546
+ :handler_opts => {:key => :length},
547
+ :type => Type::INT,
548
+ },
549
+
550
+ # bitrate
551
+ {
552
+ :name => :bitrate,
553
+ :handler => :read_audio_property,
554
+ :handler_opts => {:key => :bitrate},
555
+ :type => Type::INT,
556
+ },
557
+
558
+ # sample_rate
559
+ {
560
+ :name => :sample_rate,
561
+ :handler => :read_audio_property,
562
+ :handler_opts => {:key => :sample_rate},
563
+ :type => Type::INT,
564
+ },
565
+
566
+ # channels
567
+ {
568
+ :name => :channels,
569
+ :handler => :read_audio_property,
570
+ :handler_opts => {:key => :channels},
571
+ :type => Type::INT,
572
+ },
573
+
574
+ # copyrighted?
575
+ {
576
+ :name => :copyrighted?,
577
+ :handler => :read_audio_property,
578
+ :handler_opts => {:key => :copyrighted?},
579
+ :type => Type::BOOLEAN,
580
+ },
581
+
582
+ # layer
583
+ {
584
+ :name => :layer,
585
+ :handler => :read_audio_property,
586
+ :handler_opts => {:key => :layer},
587
+ :type => Type::INT,
588
+ },
589
+
590
+ # original?
591
+ {
592
+ :name => :original?,
593
+ :handler => :read_audio_property,
594
+ :handler_opts => {:key => :original?},
595
+ :type => Type::BOOLEAN,
596
+ },
597
+
598
+ # protection_enabled?
599
+ {
600
+ :name => :protection_enabled?,
601
+ :handler => :read_audio_property,
602
+ :handler_opts => {:key => :protection_enabled},
603
+ :type => Type::BOOLEAN,
604
+ },
381
605
  ]
382
606
  end