id3lib-ruby 0.1.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 +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
|