id3lib-ruby 0.1.0 → 0.2.0

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.
data/CHANGES CHANGED
@@ -1,14 +1,16 @@
1
- = id3lib-ruby Changes
2
-
3
- === Before release
4
-
5
- * New: Everything.
6
- * Get rid of ID3::Frame and use normal Hash instead.
7
- * Clean up ID3::Frames and Fields -> replace them with an ID3::Info module.
8
- * How to set ID3 genre?
9
- * Replace Accessors.add with normal function definitions
10
- * Document library with RDOC.
11
- * Add more frame accessor methods (maybe there are now too much?).
12
- * Added reading and writing of UTF-16 frames. Works only with ID3v2.
13
- * Renamed extension ID3Lib to ID3Lib::API and module ID3 to ID3Lib.
14
- * Finish and test gem specification.
1
+ = id3lib-ruby changes
2
+
3
+ === 0.2.0 (r21)
4
+
5
+ * Overhauled direct access methods
6
+ * Remove frames by setting them to nil, e.g. tag.title = nil
7
+ * Removed methods for rarely used frames.
8
+ * All methods use strings now, no special cases like track anymore.
9
+ * Explicit call of to_s in set_frame_text.
10
+ * More unit tests
11
+ * Added method invalid_frames which is useful to detect invalid frame
12
+ data before calling update!.
13
+
14
+ === 0.1.0 (r19)
15
+
16
+ * First release :)
data/Rakefile CHANGED
@@ -10,7 +10,7 @@ require 'rake/testtask'
10
10
  require 'rake/rdoctask'
11
11
 
12
12
 
13
- PKG_VERSION = '0.1.0'
13
+ PKG_VERSION = '0.2.0'
14
14
 
15
15
  PKG_FILES = FileList[
16
16
  'lib/**/*.rb',
data/TODO CHANGED
@@ -1,9 +1,5 @@
1
- = id3lib-ruby To Do List
1
+ = id3lib-ruby to-do list
2
2
 
3
- * Overhaul direct access methods
4
- * Implement removing frames. tag.title = nil ?
5
- * Remove methods for rarely used frames.
6
- * Use strings in all methods - get rid of exceptions.
7
- * Add method to check if frames and fields are valid.
8
3
  * Create Windows binary gem (id3lib.dll included).
4
+ * Evaluate a more object-oriented way to handle frames, instead of hashes.
9
5
  * Add UTF-8 support if id3lib can handle it.
@@ -213,7 +213,9 @@ module ID3Lib
213
213
  #
214
214
  def set_frame_text(id, text)
215
215
  remove_frame(id)
216
- self << { :id => id, :text => text }
216
+ if text
217
+ self << { :id => id, :text => text.to_s }
218
+ end
217
219
  end
218
220
 
219
221
  #
@@ -227,6 +229,9 @@ module ID3Lib
227
229
  # Updates the tag. This change can't be undone. _writetype_ specifies
228
230
  # which tag type to write and defaults to _readtype_ (see #new).
229
231
  #
232
+ # Invalid frames or frame data is ignored. Use #invalid_frames before
233
+ # update! if you want to know if you have invalid data.
234
+ #
230
235
  # Returns a number corresponding to the written tag type(s) or nil if
231
236
  # the update failed.
232
237
  #
@@ -278,6 +283,34 @@ module ID3Lib
278
283
  @tag.has_tag_type(type)
279
284
  end
280
285
 
286
+ #
287
+ # Returns an Array of invalid frames and fields. If a frame ID is
288
+ # invalid, it alone is in the resulting array. If a frame ID is valid
289
+ # but has invalid fields, the frame ID and the invalid field IDs are
290
+ # included.
291
+ #
292
+ # tag.invalid_frames
293
+ # #=> [ [:TITS], [:TALB, :invalid] ]
294
+ #
295
+ def invalid_frames
296
+ invalid = []
297
+ each do |frame|
298
+ if not info = Info.frame(frame[:id])
299
+ # Frame ID doesn't exist.
300
+ invalid << [frame[:id]]
301
+ next
302
+ end
303
+ # Frame ID is ok, but are all fields ok?
304
+ invalid_fields = frame.keys.reject { |id|
305
+ info[FIELDS].include?(id) or id == :id
306
+ }
307
+ if not invalid_fields.empty?
308
+ invalid << [frame[:id], *invalid_fields]
309
+ end
310
+ end
311
+ invalid.empty? ? nil : invalid
312
+ end
313
+
281
314
  private
282
315
 
283
316
  def read_frames
@@ -342,7 +375,7 @@ module ID3Lib
342
375
  def self.field(libframe, id)
343
376
  libframe.field(Info.field(id)[NUM])
344
377
  end
345
-
378
+
346
379
  end
347
380
 
348
381
 
@@ -4,16 +4,14 @@ module ID3Lib
4
4
  #
5
5
  # The Accessors module defines accessor methods for ID3 text frames.
6
6
  #
7
- # Have a look at the source code to see the ID3 frame ID behind an accessor.
8
- #
9
7
  # === Most used accessors
10
8
  #
11
- # Here's a list of the probably most used accessors:
9
+ # Here's a list of the most used accessors:
12
10
  #
13
11
  # * #title
14
12
  # * #performer or #artist
15
13
  # * #album
16
- # * #genre
14
+ # * #genre or #content_type
17
15
  # * #year
18
16
  # * #track
19
17
  # * #part_of_set or #disc
@@ -21,22 +19,6 @@ module ID3Lib
21
19
  # * #composer
22
20
  # * #bpm
23
21
  #
24
- # === Automatic conversion
25
- #
26
- # Some accessors automatically convert the raw text to a more
27
- # suitable type (when reading) and back (when writing). For example,
28
- # the track information is converted to an array of one or two items.
29
- #
30
- # tag.track #=> [1,12]
31
- #
32
- # and the year is an integer.
33
- #
34
- # tag.year #=> 2005
35
- #
36
- # Use the Tag#frame_text method to get the raw text.
37
- #
38
- # tag.frame_text(:TRCK) #=> "1/12"
39
- #
40
22
  module Accessors
41
23
 
42
24
  def title() frame_text(:TIT2) end
@@ -44,103 +26,60 @@ module ID3Lib
44
26
 
45
27
  def performer() frame_text(:TPE1) end
46
28
  def performer=(v) set_frame_text(:TPE1, v) end
47
- alias_method :artist, :performer
48
- alias_method :artist=, :performer=
29
+ alias artist performer
30
+ alias artist= performer=
49
31
 
50
32
  def album() frame_text(:TALB) end
51
33
  def album=(v) set_frame_text(:TALB, v) end
52
34
 
53
- def comment() frame_text(:COMM) end
54
- def comment=(v) set_frame_text(:COMM, v) end
55
-
56
35
  def genre() frame_text(:TCON) end
57
36
  def genre=(v) set_frame_text(:TCON, v) end
58
- alias_method :content_type, :genre
59
- alias_method :content_type=, :genre=
60
-
61
- def bpm() frame_text(:TBPM) end
62
- def bpm=(v) set_frame_text(:TBPM, v.to_s) end
63
-
64
- def composer() frame_text(:TCOM) end
65
- def composer=(v) set_frame_text(:TCOM, v) end
66
-
67
- def copyright() frame_text(:TCOP) end
68
- def copyright=(v) set_frame_text(:TCOP, v) end
37
+ alias content_type genre
38
+ alias content_type= genre=
69
39
 
70
- def date() frame_text(:TDAT) end
71
- def date=(v) set_frame_text(:TDAT, v) end
40
+ def year() frame_text(:TYER) end
41
+ def year=(v) set_frame_text(:TYER, v) end
72
42
 
73
- def encoding_time() frame_text(:TDEN) end
74
- def encoding_time=(v) set_frame_text(:TDEN, v) end
43
+ def track() frame_text(:TRCK) end
44
+ def track=(v) set_frame_text(:TRCK, v) end
75
45
 
76
- def playlist_delay() frame_text(:TDLY) end
77
- def playlist_delay=(v) set_frame_text(:TDLY, v) end
46
+ def part_of_set() frame_text(:TPOS) end
47
+ def part_of_set=(v) set_frame_text(:TPOS, v) end
48
+ alias disc part_of_set
49
+ alias disc= part_of_set=
78
50
 
79
- def original_release_time() frame_text(:TDOR) end
80
- def original_release_time=(v) set_frame_text(:TDOR, v) end
81
-
82
- def recording_time() frame_text(:TDRC) end
83
- def recording_time=(v) set_frame_text(:TDRC, v) end
51
+ def comment() frame_text(:COMM) end
52
+ def comment=(v) set_frame_text(:COMM, v) end
84
53
 
85
- def release_time() frame_text(:TDRL) end
86
- def release_time=(v) set_frame_text(:TDRL, v) end
54
+ # Returns an array of comment frames.
55
+ def comment_frames() select{ |f| f[:id] == :COMM } end
87
56
 
88
- def tagging_time() frame_text(:TDTG) end
89
- def tagging_time=(v) set_frame_text(:TDTG, v) end
57
+ def composer() frame_text(:TCOM) end
58
+ def composer=(v) set_frame_text(:TCOM, v) end
90
59
 
91
- def involved_people() frame_text(:TIPL) end
92
- def involved_people=(v) set_frame_text(:TIPL, v) end
60
+ def grouping() frame_text(:TIT1) end
61
+ def grouping=(v) set_frame_text(:TIT1, v) end
93
62
 
94
- def encoded_by() frame_text(:TENC) end
95
- def encoded_by=(v) set_frame_text(:TENC, v) end
63
+ def bpm() frame_text(:TBPM) end
64
+ def bpm=(v) set_frame_text(:TBPM, v.to_s) end
96
65
 
97
- def lyricist() frame_text(:TEXT) end
98
- def lyricist=(v) set_frame_text(:TEXT, v) end
66
+ def subtitle() frame_text(:TIT3) end
67
+ def subtitle=(v) set_frame_text(:TIT3, v) end
99
68
 
100
- def file_type() frame_text(:TFLT) end
101
- def file_type=(v) set_frame_text(:TFLT, v) end
69
+ def date() frame_text(:TDAT) end
70
+ def date=(v) set_frame_text(:TDAT, v) end
102
71
 
103
72
  def time() frame_text(:TIME) end
104
73
  def time=(v) set_frame_text(:TIME, v) end
105
74
 
106
- def content_group() frame_text(:TIT1) end
107
- def content_group=(v) set_frame_text(:TIT1, v) end
108
-
109
- def subtitle() frame_text(:TIT3) end
110
- def subtitle=(v) set_frame_text(:TIT3, v) end
111
-
112
- def initial_key() frame_text(:TKEY) end
113
- def initial_key=(v) set_frame_text(:TKEY, v) end
114
-
115
75
  def language() frame_text(:TLAN) end
116
76
  def language=(v) set_frame_text(:TLAN, v) end
117
77
 
118
- def audio_length() frame_text(:TLEN) end
119
- def audio_length=(v) set_frame_text(:TLEN, v) end
120
-
121
- def musician_credits() frame_text(:TMCL) end
122
- def musician_credits=(v) set_frame_text(:TMCL, v) end
123
-
124
- def media_type() frame_text(:TMED) end
125
- def media_type=(v) set_frame_text(:TMED, v) end
126
-
127
- def mood() frame_text(:TMOO) end
128
- def mood=(v) set_frame_text(:TMOO, v) end
129
-
130
- def original_title() frame_text(:TOAL) end
131
- def original_title=(v) set_frame_text(:TOAL, v) end
132
-
133
- def original_filename() frame_text(:TOFN) end
134
- def original_filename=(v) set_frame_text(:TOFN, v) end
135
-
136
- def original_lyricist() frame_text(:TOLY) end
137
- def original_lyricist=(v) set_frame_text(:TOLY, v) end
138
-
139
- def original_performer() frame_text(:TOPE) end
140
- def original_performer=(v) set_frame_text(:TOPE, v) end
78
+ def lyrics() frame_text(:USLT) end
79
+ def lyrics=(v) set_frame_text(:USLT, v) end
141
80
 
142
- def file_owner() frame_text(:TOWN) end
143
- def file_owner=(v) set_frame_text(:TOWN, v) end
81
+ def lyricist() frame_text(:TEXT) end
82
+ def lyricist=(v) set_frame_text(:TEXT, v) end
144
83
 
145
84
  def band() frame_text(:TPE2) end
146
85
  def band=(v) set_frame_text(:TPE2, v) end
@@ -148,112 +87,16 @@ module ID3Lib
148
87
  def conductor() frame_text(:TPE3) end
149
88
  def conductor=(v) set_frame_text(:TPE3, v) end
150
89
 
151
- def produced_notice() frame_text(:TPRO) end
152
- def produced_notice=(v) set_frame_text(:TPRO, v) end
90
+ def interpreted_by() frame_text(:TPE4) end
91
+ def interpreted_by=(v) set_frame_text(:TPE4, v) end
92
+ alias remixed_by interpreted_by
93
+ alias remixed_by= interpreted_by=
153
94
 
154
95
  def publisher() frame_text(:TPUB) end
155
96
  def publisher=(v) set_frame_text(:TPUB, v) end
156
97
 
157
- def internet_radio_station() frame_text(:TRSN) end
158
- def internet_radio_station=(v) set_frame_text(:TRSN, v) end
159
-
160
- def internet_radio_owner() frame_text(:TRSO) end
161
- def internet_radio_owner=(v) set_frame_text(:TRSO, v) end
162
-
163
- def album_sort_order() frame_text(:TSOA) end
164
- def album_sort_order=(v) set_frame_text(:TSOA, v) end
165
-
166
- def performer_sort_order() frame_text(:TSOP) end
167
- def performer_sort_order=(v) set_frame_text(:TSOP, v) end
168
-
169
- def title_sort_order() frame_text(:TSOT) end
170
- def title_sort_order=(v) set_frame_text(:TSOT, v) end
171
-
172
- def isrc() frame_text(:TSRC) end
173
- def isrc=(v) set_frame_text(:TSRC, v) end
174
-
175
- def encoder_settings() frame_text(:TSSE) end
176
- def encoder_settings=(v) set_frame_text(:TSSE, v) end
177
-
178
- def set_subtitle() frame_text(:TSST) end
179
- def set_subtitle=(v) set_frame_text(:TSST, v) end
180
-
181
- def terms_of_use() frame_text(:TPE2) end
182
- def terms_of_use=(v) set_frame_text(:TPE2, v) end
183
-
184
- def commercial_url() frame_text(:WCOM) end
185
- def commercial_url=(v) set_frame_text(:WCOM, v) end
186
-
187
- def copyright_url() frame_text(:WCOP) end
188
- def copyright_url=(v) set_frame_text(:WCOP, v) end
189
-
190
- def audio_file_url() frame_text(:WOAF) end
191
- def audio_file_url=(v) set_frame_text(:WOAF, v) end
192
-
193
- def performer_url() frame_text(:WOAR) end
194
- def performer_url=(v) set_frame_text(:WOAR, v) end
195
-
196
- def audio_source_url() frame_text(:WOAS) end
197
- def audio_source_url=(v) set_frame_text(:WOAS, v) end
198
-
199
- def internet_radio_url() frame_text(:WORS) end
200
- def internet_radio_url=(v) set_frame_text(:WORS, v) end
201
-
202
- def payment_url() frame_text(:WPAY) end
203
- def payment_url=(v) set_frame_text(:WPAY, v) end
204
-
205
- def publisher_url() frame_text(:WPUB) end
206
- def publisher_url=(v) set_frame_text(:WPUB, v) end
207
-
208
- # Returns an array of comment frames.
209
- def comment_frames() select{ |f| f[:id] == :COMM } end
210
-
211
- #
212
- # Returns an array of one or two numbers.
213
- #
214
- # tag.track #=> [3,11]
215
- # tag.frame_text(:TRCK) #=> "3/11"
216
- #
217
- # tag_2.track #=> [5]
218
- # tag_2.frame_text(:TRCK) #=> "5"
219
- #
220
- def track() frame_text(:TRCK).split('/').collect{ |s| s.to_i } end
221
-
222
- #
223
- # Assign either an array or a string.
224
- #
225
- # tag.track = [4,11]
226
- # tag.track = [5]
227
- # tag.track = "4/11"
228
- #
229
- def track=(v) set_frame_text(:TRCK, (v.join('/') rescue v.to_s)) end
230
-
231
- #
232
- # Returns an array of one or two numbers like #track.
233
- #
234
- def part_of_set() frame_text(:TPOS).split('/').collect{ |s| s.to_i } end
235
- alias_method :disc, :part_of_set
236
-
237
- #
238
- # Assign either an array or a string like #track=.
239
- #
240
- def part_of_set=(v) set_frame_text(:TPOS, (v.join('/') rescue v.to_s)) end
241
- alias_method :disc=, :part_of_set=
242
-
243
- #
244
- # Returns a number.
245
- #
246
- # tag.year #=> 2004
247
- #
248
- def year() frame_text(:TYER).to_i end
249
-
250
- #
251
- # Assign a number or a string.
252
- #
253
- # tag.year = 2005
254
- # tag.year = "2005"
255
- #
256
- def year=(v) set_frame_text(:TYER, v.to_s) end
98
+ def encoded_by() frame_text(:TENC) end
99
+ def encoded_by=(v) set_frame_text(:TENC, v) end
257
100
 
258
101
  end
259
102
 
@@ -25,8 +25,8 @@ class TestReading < Test::Unit::TestCase
25
25
  assert_equal 'Dummy Artist', @tag.artist
26
26
  assert_equal 'Dummy Artist', @tag.performer
27
27
  assert_equal 'Dummy Album', @tag.album
28
- assert_equal [1,10], @tag.track
29
- assert_equal 2000, @tag.year
28
+ assert_equal '1/10', @tag.track
29
+ assert_equal '2000', @tag.year
30
30
  assert_equal 'Dummy Comment', @tag.comment
31
31
  assert_equal 'Pop', @tag.genre
32
32
  end
@@ -53,4 +53,18 @@ class TestReading < Test::Unit::TestCase
53
53
  assert_equal 2038, @tag.size
54
54
  end
55
55
 
56
+ def test_invalid_frames
57
+ assert_nil @tag.invalid_frames
58
+
59
+ @tag << { :id => :TITS }
60
+ assert_equal [[:TITS]], @tag.invalid_frames
61
+
62
+ @tag << { :id => :TALB, :invalid => 'text' }
63
+ assert_equal [[:TITS], [:TALB, :invalid]], @tag.invalid_frames
64
+
65
+ @tag << { :id => :APIC, :text => 'invalid' }
66
+ assert_equal [[:TITS], [:TALB, :invalid], [:APIC, :text]],
67
+ @tag.invalid_frames
68
+ end
69
+
56
70
  end
@@ -53,58 +53,43 @@ class TestWriting < Test::Unit::TestCase
53
53
  assert_equal genre_id, @tag.genre
54
54
  end
55
55
 
56
- # The track can be set in various ways. Test them all :)
57
56
  def test_track
58
- @tag.track = 1
59
- assert_equal [1], @tag.track
60
- @tag.update!
61
- assert_equal [1], @tag.track
62
- reload!
63
- assert_equal [1], @tag.track
64
-
65
- @tag.track = [2]
66
- assert_equal [2], @tag.track
67
- @tag.update!
68
- assert_equal [2], @tag.track
69
- reload!
70
- assert_equal [2], @tag.track
71
-
72
- @tag.track = [3,10]
73
- assert_equal [3,10], @tag.track
74
- @tag.update!
75
- assert_equal [3,10], @tag.track
76
- reload!
77
- assert_equal [3,10], @tag.track
78
-
79
57
  @tag.track = '4'
80
- assert_equal [4], @tag.track
58
+ assert_equal '4', @tag.track
81
59
  @tag.update!
82
- assert_equal [4], @tag.track
60
+ assert_equal '4', @tag.track
83
61
  reload!
84
- assert_equal [4], @tag.track
85
-
62
+ assert_equal '4', @tag.track
63
+
86
64
  @tag.track = '5/12'
87
- assert_equal [5,12], @tag.track
65
+ assert_equal '5/12', @tag.track
66
+ @tag.update!
67
+ assert_equal '5/12', @tag.track
68
+ reload!
69
+ assert_equal '5/12', @tag.track
70
+
71
+ @tag.track = 6
72
+ assert_equal '6', @tag.track
88
73
  @tag.update!
89
- assert_equal [5,12], @tag.track
74
+ assert_equal '6', @tag.track
90
75
  reload!
91
- assert_equal [5,12], @tag.track
76
+ assert_equal '6', @tag.track
92
77
  end
93
78
 
94
79
  def test_year
95
- @tag.year = 2001
96
- assert_equal 2001, @tag.year
80
+ @tag.year = '2001'
81
+ assert_equal '2001', @tag.year
97
82
  @tag.update!
98
- assert_equal 2001, @tag.year
83
+ assert_equal '2001', @tag.year
99
84
  reload!
100
- assert_equal 2001, @tag.year
101
-
102
- @tag.year = '2002'
103
- assert_equal 2002, @tag.year
85
+ assert_equal '2001', @tag.year
86
+
87
+ @tag.year = 2002
88
+ assert_equal '2002', @tag.year
104
89
  @tag.update!
105
- assert_equal 2002, @tag.year
90
+ assert_equal '2002', @tag.year
106
91
  reload!
107
- assert_equal 2002, @tag.year
92
+ assert_equal '2002', @tag.year
108
93
  end
109
94
 
110
95
  def test_comments
@@ -151,6 +136,11 @@ class TestWriting < Test::Unit::TestCase
151
136
  assert_nil @tag.frame(:TIT2)
152
137
  end
153
138
 
139
+ def test_remove_frame_with_direct_access
140
+ @tag.title = nil
141
+ assert_nil @tag.frame(:TIT2)
142
+ end
143
+
154
144
  def test_wrong_frame
155
145
  l = @tag.length
156
146
  @tag << {:id => :WRONG, :text => "Test"}
@@ -210,5 +200,38 @@ class TestWriting < Test::Unit::TestCase
210
200
  @tag.performer = "Nobody"
211
201
  assert_equal nil, @tag.update!
212
202
  end
213
-
203
+
204
+ def test_accessors
205
+ accessors = %w[
206
+ title performer album genre year track part_of_set comment composer
207
+ grouping bpm subtitle date time language lyrics lyricist band
208
+ conductor interpreted_by publisher encoded_by
209
+ ]
210
+ do_tests_for_accessors(accessors)
211
+ end
212
+
213
+ def test_accessor_aliases
214
+ aliases = %w[ artist content_type disc remixed_by ]
215
+ do_tests_for_accessors(aliases)
216
+ end
217
+
218
+ def do_tests_for_accessors(accessors)
219
+ accessors.each do |m|
220
+ @tag.send("#{m}=", "#{m} test")
221
+ assert_equal "#{m} test", @tag.send(m)
222
+ end
223
+
224
+ @tag.update!
225
+
226
+ accessors.each do |m|
227
+ assert_equal "#{m} test", @tag.send(m)
228
+ end
229
+
230
+ reload!
231
+
232
+ accessors.each do |m|
233
+ assert_equal "#{m} test", @tag.send(m)
234
+ end
235
+ end
236
+
214
237
  end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: id3lib-ruby
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.1.0
7
- date: 2006-04-24 00:00:00 +02:00
6
+ version: 0.2.0
7
+ date: 2006-05-07 00:00:00 +02:00
8
8
  summary: id3lib-ruby provides a Ruby interface to the id3lib C++ library for easily editing ID3 tags (v1 and v2) like with pyid3lib.
9
9
  require_paths:
10
10
  - lib