id3lib-ruby 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +14 -0
- data/README +91 -0
- data/Rakefile +108 -0
- data/TODO +9 -0
- data/ext/extconf.rb +6 -0
- data/ext/id3lib_api_wrap.cxx +1950 -0
- data/lib/id3lib.rb +349 -0
- data/lib/id3lib/accessors.rb +260 -0
- data/lib/id3lib/info.rb +253 -0
- data/setup.rb +1585 -0
- data/test/data/cover.jpg +0 -0
- data/test/data/sample.mp3 +0 -0
- data/test/data/unicode.mp3 +0 -0
- data/test/test_reading.rb +56 -0
- data/test/test_writing.rb +214 -0
- metadata +63 -0
data/lib/id3lib.rb
ADDED
@@ -0,0 +1,349 @@
|
|
1
|
+
|
2
|
+
require 'id3lib_api'
|
3
|
+
require 'id3lib/info'
|
4
|
+
require 'id3lib/accessors'
|
5
|
+
|
6
|
+
|
7
|
+
#
|
8
|
+
# This module includes all the classes and constants of id3lib-ruby.
|
9
|
+
# Have a look at ID3Lib::Tag for an introduction on how to use this library.
|
10
|
+
#
|
11
|
+
module ID3Lib
|
12
|
+
|
13
|
+
# ID3 version 1. All V constants can be used with the methods
|
14
|
+
# new, update! or strip! of ID3Lib::Tag.
|
15
|
+
V1 = 1
|
16
|
+
# ID3 version 2
|
17
|
+
V2 = 2
|
18
|
+
# No tag type
|
19
|
+
V_NONE = 0
|
20
|
+
# All tag types
|
21
|
+
V_ALL = -1
|
22
|
+
# Both ID3 versions
|
23
|
+
V_BOTH = V1 | V2
|
24
|
+
|
25
|
+
NUM = 0
|
26
|
+
ID = 1
|
27
|
+
DESC = 2
|
28
|
+
FIELDS = 3
|
29
|
+
|
30
|
+
#
|
31
|
+
# This class is the main frontend of the library.
|
32
|
+
# Use it to read and write ID3 tag data of files.
|
33
|
+
#
|
34
|
+
# === Example of use
|
35
|
+
#
|
36
|
+
# tag = ID3Lib::Tag.read('shy_boy.mp3')
|
37
|
+
#
|
38
|
+
# # Remove comments
|
39
|
+
# tag.delete_if{ |frame| frame[:id] == :COMM }
|
40
|
+
#
|
41
|
+
# # Set year
|
42
|
+
# tag.year #=> 2000
|
43
|
+
# tag.year = 2005
|
44
|
+
#
|
45
|
+
# # Apply changes
|
46
|
+
# tag.update!
|
47
|
+
#
|
48
|
+
# === Working with tags
|
49
|
+
#
|
50
|
+
# You can use a ID3Lib::Tag object like an array. In fact, it is a subclass
|
51
|
+
# of Array. An ID3Lib::Tag contains frames which are stored as hashes,
|
52
|
+
# with field IDs as keys and field values as values. The frame IDs like TIT2
|
53
|
+
# are the ones specified by the ID3 standard. If you don't know these IDs,
|
54
|
+
# you probably want to use the accessor methods described afterwards, which
|
55
|
+
# have a more natural naming.
|
56
|
+
#
|
57
|
+
# tag.each do |frame|
|
58
|
+
# p frame
|
59
|
+
# end
|
60
|
+
# #=> {:id => :TIT2, :text => "Shy Boy", :textenc => 0}
|
61
|
+
# #=> {:id => :TPE1, :text => "Katie Melua", :textenc => 0}
|
62
|
+
# #=> {:id => :TALB, :text => "Piece By Piece", :textenc => 0}
|
63
|
+
# #=> {:id => :TRCK, :text => "1/12", :textenc => 0}
|
64
|
+
# #=> {:id => :TYER, :text => "2005", :textenc => 0}
|
65
|
+
# #=> {:id => :TCON, :text => "Jazz/Blues", :textenc => 0}
|
66
|
+
#
|
67
|
+
# === Get and set frames
|
68
|
+
#
|
69
|
+
# There are a number of accessors for text frames like
|
70
|
+
# title, performer, album, track, year, comment and genre. Have a look
|
71
|
+
# at ID3Lib::Accessors for a complete list.
|
72
|
+
#
|
73
|
+
# tag.title #=> "Shy Boi"
|
74
|
+
#
|
75
|
+
# tag.title = 'Shy Boy'
|
76
|
+
# tag.title #=> "Shy Boy"
|
77
|
+
#
|
78
|
+
# tag.track #=> [1,12]
|
79
|
+
# tag.year #=> 2005
|
80
|
+
#
|
81
|
+
# You can always read and write the raw text if you want. You just have
|
82
|
+
# to use the "manual access". It is generally encouraged to use the
|
83
|
+
# #frame_text method where possible, because the other two result in
|
84
|
+
# an exception when the frame isn't found.
|
85
|
+
#
|
86
|
+
# tag.frame_text(:TRCK) #=> "1/12"
|
87
|
+
# tag.frame_text(:TLAN) #=> nil
|
88
|
+
#
|
89
|
+
# tag.frame(:TRCK)[:text] #=> "1/12"
|
90
|
+
# # Raises an exception, because nil[:text] isn't possible:
|
91
|
+
# tag.frame(:TLAN)[:text]
|
92
|
+
#
|
93
|
+
# tag.find{ |f| f[:id] == :TRCK }[:text] #=> "1/12"
|
94
|
+
# # Also raises an exception:
|
95
|
+
# tag.find{ |f| f[:id] == :TLAN }[:text]
|
96
|
+
#
|
97
|
+
# Because only text frames can be set with accessors, you have to add
|
98
|
+
# special frames by hand.
|
99
|
+
#
|
100
|
+
# # Add two comments
|
101
|
+
# tag << {:id => :COMM, :text => 'chunky bacon'}
|
102
|
+
# tag << {:id => :COMM, :text => 'really.'}
|
103
|
+
#
|
104
|
+
# # Add an attached picture
|
105
|
+
# cover = {
|
106
|
+
# :id => :APIC,
|
107
|
+
# :mimetype => 'image/jpeg',
|
108
|
+
# :picturetype => 3,
|
109
|
+
# :description => 'A pretty picture',
|
110
|
+
# :textenc => 0,
|
111
|
+
# :data => File.read('cover.jpg')
|
112
|
+
# }
|
113
|
+
# tag << cover
|
114
|
+
#
|
115
|
+
# === Get information about frames
|
116
|
+
#
|
117
|
+
# In the last example we added an APIC frame. How can we know what data
|
118
|
+
# we have to store in the APIC hash?
|
119
|
+
#
|
120
|
+
# ID3Lib::Info.frame(:APIC)[3]
|
121
|
+
# #=> [:textenc, :mimetype, :picturetype, :description, :data]
|
122
|
+
#
|
123
|
+
# We see, the last element of the info array obtained through
|
124
|
+
# ID3Lib::Info.frame is an array of field IDs needed by APIC.
|
125
|
+
#
|
126
|
+
# Have a look at the ID3Lib::Info module for detailed information.
|
127
|
+
#
|
128
|
+
# === Write changes to file
|
129
|
+
#
|
130
|
+
# When you've finished modifying a tag, don't forget to call #update! to
|
131
|
+
# write the modifications back to the file. You have to check the return
|
132
|
+
# value of update!, it returns nil on failure. This probably means that
|
133
|
+
# the file is not writeable or cannot be created.
|
134
|
+
#
|
135
|
+
# tag.update!
|
136
|
+
#
|
137
|
+
# === Getting rid of a tag
|
138
|
+
#
|
139
|
+
# Use the #strip! method to completely remove a tag from a file.
|
140
|
+
#
|
141
|
+
# tag.strip!
|
142
|
+
#
|
143
|
+
class Tag < Array
|
144
|
+
|
145
|
+
include Accessors
|
146
|
+
|
147
|
+
attr_accessor :padding
|
148
|
+
|
149
|
+
#
|
150
|
+
# Create a new Tag. When a _filename_ is supplied, the tag of the file
|
151
|
+
# is read. _tagtype_ specifies the tag type to read and defaults to
|
152
|
+
# V_ALL.
|
153
|
+
# Use one of ID3Lib::V1, ID3Lib::V2, ID3Lib::V_BOTH or ID3Lib::V_ALL.
|
154
|
+
#
|
155
|
+
# tag = ID3Lib::Tag.new('shy_boy.mp3')
|
156
|
+
#
|
157
|
+
# Only read ID3v1 tag:
|
158
|
+
#
|
159
|
+
# id3v1_tag = ID3Lib::Tag.new('piece_by_piece.mp3', ID3Lib::V1)
|
160
|
+
#
|
161
|
+
def initialize(filename, readtype=V_ALL)
|
162
|
+
@filename = filename
|
163
|
+
@readtype = readtype
|
164
|
+
@padding = true
|
165
|
+
|
166
|
+
@tag = API::Tag.new
|
167
|
+
@tag.link(@filename, @readtype)
|
168
|
+
read_frames
|
169
|
+
end
|
170
|
+
|
171
|
+
#
|
172
|
+
# Returns an estimate of the number of bytes required to store the tag
|
173
|
+
# data.
|
174
|
+
#
|
175
|
+
def size
|
176
|
+
@tag.size
|
177
|
+
end
|
178
|
+
|
179
|
+
#
|
180
|
+
# Simple shortcut for getting a frame by its _id_.
|
181
|
+
#
|
182
|
+
# tag.frame(:TIT2)
|
183
|
+
# #=> {:id => :TIT2, :text => "Shy Boy", :textenc => 0}
|
184
|
+
#
|
185
|
+
# is the same as:
|
186
|
+
#
|
187
|
+
# tag.find{ |f| f[:id] == :TIT2 }
|
188
|
+
#
|
189
|
+
def frame(id)
|
190
|
+
find{ |f| f[:id] == id }
|
191
|
+
end
|
192
|
+
|
193
|
+
#
|
194
|
+
# Get the text of a frame specified by _id_. Returns nil if the
|
195
|
+
# frame can't be found.
|
196
|
+
#
|
197
|
+
# tag.find{ |f| f[:id] == :TIT2 }[:text] #=> "Shy Boy"
|
198
|
+
# tag.frame_text(:TIT2) #=> "Shy Boy"
|
199
|
+
#
|
200
|
+
# tag.find{ |f| f[:id] == :TLAN } #=> nil
|
201
|
+
# tag.frame_text(:TLAN) #=> nil
|
202
|
+
#
|
203
|
+
def frame_text(id)
|
204
|
+
f = frame(id)
|
205
|
+
f ? f[:text] : nil
|
206
|
+
end
|
207
|
+
|
208
|
+
#
|
209
|
+
# Set the text of a frame. First, all frames with the specified _id_ are
|
210
|
+
# deleted and then a new frame with _text_ is appended.
|
211
|
+
#
|
212
|
+
# tag.set_frame_text(:TLAN, 'eng')
|
213
|
+
#
|
214
|
+
def set_frame_text(id, text)
|
215
|
+
remove_frame(id)
|
216
|
+
self << { :id => id, :text => text }
|
217
|
+
end
|
218
|
+
|
219
|
+
#
|
220
|
+
# Remove all frames with the specified _id_.
|
221
|
+
#
|
222
|
+
def remove_frame(id)
|
223
|
+
delete_if{ |f| f[:id] == id }
|
224
|
+
end
|
225
|
+
|
226
|
+
#
|
227
|
+
# Updates the tag. This change can't be undone. _writetype_ specifies
|
228
|
+
# which tag type to write and defaults to _readtype_ (see #new).
|
229
|
+
#
|
230
|
+
# Returns a number corresponding to the written tag type(s) or nil if
|
231
|
+
# the update failed.
|
232
|
+
#
|
233
|
+
# tag.update!
|
234
|
+
# id3v1_tag.update!(ID3Lib::V1)
|
235
|
+
#
|
236
|
+
def update!(writetype=@readtype)
|
237
|
+
@tag.strip(writetype)
|
238
|
+
# The following two lines are necessary because of the weird
|
239
|
+
# behaviour of id3lib.
|
240
|
+
@tag.clear
|
241
|
+
@tag.link(@filename, writetype)
|
242
|
+
|
243
|
+
delete_if do |frame|
|
244
|
+
frame_info = Info.frame(frame[:id])
|
245
|
+
next true if not frame_info
|
246
|
+
libframe = API::Frame.new(frame_info[NUM])
|
247
|
+
Frame.write(frame, libframe)
|
248
|
+
@tag.add_frame(libframe)
|
249
|
+
false
|
250
|
+
end
|
251
|
+
|
252
|
+
@tag.set_padding(@padding)
|
253
|
+
tags = @tag.update(writetype)
|
254
|
+
return tags == 0 ? nil : tags
|
255
|
+
end
|
256
|
+
|
257
|
+
#
|
258
|
+
# Strip tag from file. This is dangerous because you lose all tag
|
259
|
+
# information. Specify _striptag_ to only strip a certain tag type.
|
260
|
+
# You don't have to call #update! after #strip!.
|
261
|
+
#
|
262
|
+
# tag.strip!
|
263
|
+
# another_tag.strip!(ID3Lib::V1)
|
264
|
+
#
|
265
|
+
def strip!(striptype=V_ALL)
|
266
|
+
clear
|
267
|
+
tags = @tag.strip(striptype)
|
268
|
+
@tag.clear
|
269
|
+
@tag.link(@filename, @readtype)
|
270
|
+
tags
|
271
|
+
end
|
272
|
+
|
273
|
+
#
|
274
|
+
# Check if there is a tag of type _type_.
|
275
|
+
#
|
276
|
+
def has_tag?(type=V2)
|
277
|
+
@tag.link(@filename, V_ALL)
|
278
|
+
@tag.has_tag_type(type)
|
279
|
+
end
|
280
|
+
|
281
|
+
private
|
282
|
+
|
283
|
+
def read_frames
|
284
|
+
iterator = @tag.iterator_new
|
285
|
+
while libframe = @tag.iterator_next_frame(iterator)
|
286
|
+
self << Frame.read(libframe)
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
end
|
291
|
+
|
292
|
+
|
293
|
+
module Frame #:nodoc:
|
294
|
+
|
295
|
+
def self.read(libframe)
|
296
|
+
frame = {}
|
297
|
+
info = Info.frame(libframe.num)
|
298
|
+
frame[:id] = info[ID]
|
299
|
+
if info[FIELDS].include?(:textenc)
|
300
|
+
textenc = field(libframe, :textenc).integer
|
301
|
+
frame[:textenc] = textenc
|
302
|
+
end
|
303
|
+
info[FIELDS].each do |field_id|
|
304
|
+
next if field_id == :textenc
|
305
|
+
libfield = field(libframe, field_id)
|
306
|
+
frame[field_id] = if textenc and textenc > 0
|
307
|
+
libfield.unicode
|
308
|
+
else
|
309
|
+
case Info::FieldType[libfield.type]
|
310
|
+
when :integer : libfield.integer
|
311
|
+
when :binary : libfield.binary
|
312
|
+
when :text : libfield.ascii
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|
316
|
+
frame
|
317
|
+
end
|
318
|
+
|
319
|
+
def self.write(frame, libframe)
|
320
|
+
textenc = frame[:textenc]
|
321
|
+
field(libframe, :textenc).set_integer(textenc) if textenc
|
322
|
+
frame.each do |field_id, value|
|
323
|
+
unless Info.frame(frame[:id])[FIELDS].include?(field_id)
|
324
|
+
# TODO: Add method to check if frames are valid.
|
325
|
+
next
|
326
|
+
end
|
327
|
+
next if field_id == :textenc
|
328
|
+
libfield = field(libframe, field_id)
|
329
|
+
if textenc and textenc > 0
|
330
|
+
libfield.set_encoding(textenc)
|
331
|
+
libfield.set_unicode(value)
|
332
|
+
else
|
333
|
+
case Info::FieldType[libfield.type]
|
334
|
+
when :integer : libfield.set_integer(value)
|
335
|
+
when :binary : libfield.set_binary(value)
|
336
|
+
when :text : libfield.set_ascii(value)
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
def self.field(libframe, id)
|
343
|
+
libframe.field(Info.field(id)[NUM])
|
344
|
+
end
|
345
|
+
|
346
|
+
end
|
347
|
+
|
348
|
+
|
349
|
+
end
|
@@ -0,0 +1,260 @@
|
|
1
|
+
|
2
|
+
module ID3Lib
|
3
|
+
|
4
|
+
#
|
5
|
+
# The Accessors module defines accessor methods for ID3 text frames.
|
6
|
+
#
|
7
|
+
# Have a look at the source code to see the ID3 frame ID behind an accessor.
|
8
|
+
#
|
9
|
+
# === Most used accessors
|
10
|
+
#
|
11
|
+
# Here's a list of the probably most used accessors:
|
12
|
+
#
|
13
|
+
# * #title
|
14
|
+
# * #performer or #artist
|
15
|
+
# * #album
|
16
|
+
# * #genre
|
17
|
+
# * #year
|
18
|
+
# * #track
|
19
|
+
# * #part_of_set or #disc
|
20
|
+
# * #comment or #comment_frames
|
21
|
+
# * #composer
|
22
|
+
# * #bpm
|
23
|
+
#
|
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
|
+
module Accessors
|
41
|
+
|
42
|
+
def title() frame_text(:TIT2) end
|
43
|
+
def title=(v) set_frame_text(:TIT2, v) end
|
44
|
+
|
45
|
+
def performer() frame_text(:TPE1) end
|
46
|
+
def performer=(v) set_frame_text(:TPE1, v) end
|
47
|
+
alias_method :artist, :performer
|
48
|
+
alias_method :artist=, :performer=
|
49
|
+
|
50
|
+
def album() frame_text(:TALB) end
|
51
|
+
def album=(v) set_frame_text(:TALB, v) end
|
52
|
+
|
53
|
+
def comment() frame_text(:COMM) end
|
54
|
+
def comment=(v) set_frame_text(:COMM, v) end
|
55
|
+
|
56
|
+
def genre() frame_text(:TCON) end
|
57
|
+
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
|
69
|
+
|
70
|
+
def date() frame_text(:TDAT) end
|
71
|
+
def date=(v) set_frame_text(:TDAT, v) end
|
72
|
+
|
73
|
+
def encoding_time() frame_text(:TDEN) end
|
74
|
+
def encoding_time=(v) set_frame_text(:TDEN, v) end
|
75
|
+
|
76
|
+
def playlist_delay() frame_text(:TDLY) end
|
77
|
+
def playlist_delay=(v) set_frame_text(:TDLY, v) end
|
78
|
+
|
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
|
84
|
+
|
85
|
+
def release_time() frame_text(:TDRL) end
|
86
|
+
def release_time=(v) set_frame_text(:TDRL, v) end
|
87
|
+
|
88
|
+
def tagging_time() frame_text(:TDTG) end
|
89
|
+
def tagging_time=(v) set_frame_text(:TDTG, v) end
|
90
|
+
|
91
|
+
def involved_people() frame_text(:TIPL) end
|
92
|
+
def involved_people=(v) set_frame_text(:TIPL, v) end
|
93
|
+
|
94
|
+
def encoded_by() frame_text(:TENC) end
|
95
|
+
def encoded_by=(v) set_frame_text(:TENC, v) end
|
96
|
+
|
97
|
+
def lyricist() frame_text(:TEXT) end
|
98
|
+
def lyricist=(v) set_frame_text(:TEXT, v) end
|
99
|
+
|
100
|
+
def file_type() frame_text(:TFLT) end
|
101
|
+
def file_type=(v) set_frame_text(:TFLT, v) end
|
102
|
+
|
103
|
+
def time() frame_text(:TIME) end
|
104
|
+
def time=(v) set_frame_text(:TIME, v) end
|
105
|
+
|
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
|
+
def language() frame_text(:TLAN) end
|
116
|
+
def language=(v) set_frame_text(:TLAN, v) end
|
117
|
+
|
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
|
141
|
+
|
142
|
+
def file_owner() frame_text(:TOWN) end
|
143
|
+
def file_owner=(v) set_frame_text(:TOWN, v) end
|
144
|
+
|
145
|
+
def band() frame_text(:TPE2) end
|
146
|
+
def band=(v) set_frame_text(:TPE2, v) end
|
147
|
+
|
148
|
+
def conductor() frame_text(:TPE3) end
|
149
|
+
def conductor=(v) set_frame_text(:TPE3, v) end
|
150
|
+
|
151
|
+
def produced_notice() frame_text(:TPRO) end
|
152
|
+
def produced_notice=(v) set_frame_text(:TPRO, v) end
|
153
|
+
|
154
|
+
def publisher() frame_text(:TPUB) end
|
155
|
+
def publisher=(v) set_frame_text(:TPUB, v) end
|
156
|
+
|
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
|
257
|
+
|
258
|
+
end
|
259
|
+
|
260
|
+
end
|