id3lib-ruby 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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