Class: Id3Taginator::Id3v2Tag

Direct Known Subclasses

Id3v22Tag, Id3v23Tag, Id3v24Tag

Constant Summary collapse

IDENTIFIER =
'ID3'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Frames::CustomFrames

#add_custom_frame, #custom_frame, #remove_custom_frame

Methods included from Frames::Frameable

#find_frame, #find_frames, #set_frame_fields, #set_frame_fields_by_selector, #unsupported_frame

Methods included from Frames::PrivateFrames

#private_frames, #private_frames=, #remove_private_frame

Methods included from Frames::GroupingFrames

#group_identifications, #group_identifications=, #grouping, #grouping=, #remove_group_identification, #remove_grouping

Methods included from Frames::EncryptionFrames

#audio_encryptions, #audio_encryptions=, #encryption_methods, #encryption_methods=, #remove_audio_encryption, #remove_encryption_method

Methods included from Frames::ToSFrames

#ownership, #ownership=, #remove_ownership, #remove_terms_of_use, #terms_of_use, #terms_of_use=

Methods included from Frames::BufferFrames

#recommended_buffer_size, #recommended_buffer_size=, #remove_recommended_buffer_size

Methods included from Frames::CountFrames

#play_counter, #play_counter=, #popularity, #popularity=, #remove_play_counter, #remove_popularity

Methods included from Frames::GeoFrames

#encapsulated_object=, #encapsulated_objects, #remove_encapsulated_object

Methods included from Frames::PictureFrames

#pictures, #pictures=, #remove_picture

Methods included from Frames::CommentFrames

#comment=, #comments, #remove_comment

Methods included from Frames::LyricsFrames

#remove_unsync_lyrics, #unsync_lyrics, #unsync_lyrics=

Methods included from Frames::McdiFrames

#music_cd_identifier, #music_cd_identifier=, #remove_music_cd_identifier

Methods included from Frames::IplFrames

#involved_people, #involved_people=, #remove_involved_people

Methods included from Frames::UrlFrames

#commercial_information_url, #commercial_information_url=, #copyright_information_url, #copyright_information_url=, #official_artist_url, #official_artist_url=, #official_audio_file_url, #official_audio_file_url=, #official_publisher_webpage, #official_publisher_webpage=, #official_radio_station_homepage, #official_radio_station_homepage=, #official_source_url, #official_source_url=, #payment_url, #payment_url=, #remove_commercial_information_url, #remove_copyright_information_url, #remove_official_artist_url, #remove_official_audio_file_url, #remove_official_publisher_webpage, #remove_official_radio_station_homepage, #remove_official_source_url, #remove_payment_url, #remove_user_custom_url_link, #user_custom_url_link=, #user_custom_url_links

Methods included from Frames::TextFrames

#album, #album=, #album_artist, #album_artist=, #album_sort_order, #album_sort_order=, #artists, #artists=, #bpm, #bpm=, #composers, #composers=, #conductor, #conductor=, #content_group_description, #content_group_description=, #copyright, #copyright=, #date, #date=, #encoded_by, #encoded_by=, #encoder, #encoder=, #file_owner, #file_owner=, #file_type, #file_type=, #genres, #genres=, #initial_key, #initial_key=, #internet_radio_station_name, #internet_radio_station_name=, #isrc, #isrc=, #languages, #languages=, #length, #length=, #media_type, #media_type=, #modified_by, #modified_by=, #original_album, #original_album=, #original_artists, #original_artists=, #original_filename, #original_filename=, #original_release_year, #original_release_year=, #original_writers, #original_writers=, #part_of_set, #part_of_set=, #performer_sort_order, #performer_sort_order=, #playlist_delay, #playlist_delay=, #publisher, #publisher=, #recording_dates, #recording_dates=, #remove_album, #remove_album_artist, #remove_album_sort_order, #remove_artists, #remove_bpm, #remove_composers, #remove_conductor, #remove_content_group_description, #remove_copyright, #remove_date, #remove_encoded_by, #remove_encoder, #remove_file_owner, #remove_file_type, #remove_genres, #remove_initial_key, #remove_internet_radio_station_name, #remove_isrc, #remove_languages, #remove_length, #remove_media_type, #remove_modified_by, #remove_original_album, #remove_original_artists, #remove_original_filename, #remove_original_release_year, #remove_original_writers, #remove_part_of_set, #remove_performer_sort_order, #remove_playlist_delay, #remove_publisher, #remove_recording_dates, #remove_size, #remove_subtitle, #remove_time, #remove_title, #remove_title_sort_order, #remove_track_number, #remove_user_custom_text_information, #remove_writers, #remove_year, #size, #size=, #subtitle, #subtitle=, #time, #time=, #title, #title=, #title_sort_order, #title_sort_order=, #track_number, #track_number=, #user_custom_text_information, #user_custom_text_information=, #writers, #writers=, #year, #year=

Methods included from Frames::UfidFrames

#remove_unique_file_identifier, #unique_file_identifiers, #unique_file_identifiers=

Constructor Details

#initialize(header_size, major_version, minor_version, flags, tag_size, frames, extended_header) ⇒ Id3v2Tag

Constructor

Parameters:

  • header_size (Integer)

    number of bytes for the Header, usually 6 for v2 and 10 for v3 and v4

  • major_version (Integer)

    the major version, in v2..[minor]

  • minor_version (Integer)

    the minor version, in v2..[minor]

  • flags (Header::Id3v2Flags)

    the 2 Byte header flags wrapped in the entity

  • tag_size (Integer)

    number of bytes the excluding header/footer of the tag

  • frames (Array<Frames::Id3TagFrame>)

    array of frames of the id3tag

  • extended_header (Header::Id3v23ExtendedHeader, Header::Id3v24ExtendedHeader, nil)

    the extended header of present or nil otherwise



93
94
95
96
97
98
99
100
101
# File 'lib/id3taginator/id3v2_tag.rb', line 93

def initialize(header_size, major_version, minor_version, flags, tag_size, frames, extended_header)
  @header_size = header_size
  @major_version = major_version
  @minor_version = minor_version
  @flags = flags
  @tag_size = tag_size
  @extended_header = extended_header
  @frames = frames
end

Instance Attribute Details

#options=(value) ⇒ Object (writeonly)

Sets the attribute options

Parameters:

  • value

    the value to set the attribute options to.



24
25
26
# File 'lib/id3taginator/id3v2_tag.rb', line 24

def options=(value)
  @options = value
end

Class Method Details

.build_for_version(version, options) ⇒ Id3v22Tag, ...

builds an empty id3tag for the given version

Parameters:

  • version (Integer)

    the id3tag major version 2,3 or 4

  • options (Options::Options)

    the options to use

Returns:



70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/id3taginator/id3v2_tag.rb', line 70

def self.build_for_version(version, options)
  case version
  when 2
    Id3v22Tag.build_empty(options)
  when 3
    Id3v23Tag.build_empty(options)
  when 4
    Id3v24Tag.build_empty(options)
  else
    raise Errors::Id3TagError, "Id3v2.#{version} is not supported."
  end
end

.build_from_file(file, options) ⇒ Id3v2Tag

builds an id3tag from the given file stream and the passed options

Parameters:

  • file (StringIO, IO, File)

    the file stream

  • options (Options::Options)

    options that should be used

Returns:

  • (Id3v2Tag)

    the id3v2tag object,the specific object is determined by the tag version

Raises:



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/id3taginator/id3v2_tag.rb', line 44

def self.build_from_file(file, options)
  file.seek(0)
  tag = file.read(3)
  raise Errors::Id3TagError, "#{tag} is no valid ID3v2 tag. Tag seems corrupted." unless tag == IDENTIFIER

  major_version = file.readbyte
  minor_version = file.readbyte
  flags = Header::Id3v2Flags.new(file.readbyte)
  tag_size = Util::MathUtil.to_32_synchsafe_integer(file.read(4)&.bytes)

  tag_data = file.read(tag_size)
  raise Errors::Id3TagError, 'There is no Tag data to read. ID3v2 tag seems to be invalid.' if tag_data.nil?

  tag_data = Util::SyncUtil.undo_synchronization(StringIO.new(tag_data)) if flags.unsynchronized?

  id3v2_tag = id3v2_tag_for_version(major_version)

  id3v2_tag.new(minor_version, flags, tag_size, StringIO.new(tag_data), options)
end

.id3v2_tag?(file) ⇒ Boolean

checks if the given stream contains a id3v2 tag

Parameters:

  • file (StringIO, IO, File)

    the file stream to check

Returns:

  • (Boolean)

    true if contains an id3v2 tag, else false



31
32
33
34
35
36
# File 'lib/id3taginator/id3v2_tag.rb', line 31

def self.id3v2_tag?(file)
  tag = file.read(3)
  file.seek(0)

  tag == IDENTIFIER
end

Instance Method Details

#add_frame(frame) ⇒ Object

adds a new frame. There will be no validity checks, even invalid frames can be added, essentially rendering the Id3 tag broken

Parameters:

Raises:



128
129
130
131
132
# File 'lib/id3taginator/id3v2_tag.rb', line 128

def add_frame(frame)
  raise Errors::Id3TagError, 'The given frame is no Id3v2Frame.' unless frame.is_a?(Frames::Id3v2Frame)

  @frames << frame
end

#add_size_tag_if_not_present(audio_size) ⇒ Object

adds the size tag if not present. If v2.4, the option ignore_v24_frame_error must be true

Parameters:

  • audio_size (Integer)

    the audio size bytes



158
159
160
161
162
163
164
165
166
167
# File 'lib/id3taginator/id3v2_tag.rb', line 158

def add_size_tag_if_not_present(audio_size)
  return nil unless @options.add_size_frame

  return nil if @major_version == 4 && !@options.ignore_v24_frame_error

  size_frame = size
  return nil unless size_frame.nil?

  self.size = audio_size
end

#frames(frame_id) ⇒ Array<Frames::Id3v2Frame>

selects all frames with the given frame id

Returns:

  • (Array<Frames::Id3v2Frame>)

    an array of Id3v2Frames such as CustomFrame, AlbumFrame etc.



120
121
122
# File 'lib/id3taginator/id3v2_tag.rb', line 120

def frames(frame_id)
  @frames.select { |f| f.frame_id == frame_id }
end

#number_of_framesInteger

returns the number of frames for this tag

Returns:

  • (Integer)

    number of frames



137
138
139
# File 'lib/id3taginator/id3v2_tag.rb', line 137

def number_of_frames
  @frames.length
end

#parse_frames(file, version = 3) ⇒ Array<Frames::Id3v2Frame>

parses the frames for the given id3v2 tag version

Parameters:

  • file (StringIO, IO, File)

    the file or StringIO stream the bytes can be fetched from

  • version (Integer) (defaults to: 3)

Returns:



226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/id3taginator/id3v2_tag.rb', line 226

def parse_frames(file, version = 3)
  generator = Frames::Id3v2FrameFactory.new(file, version, @options)

  result = []
  frame = generator.next_frame
  until frame.nil?
    result << frame
    frame = generator.next_frame
  end

  result
end

#to_bytesString

dumps the tag to a byte string. This dump already takes unsynchronization, padding and all other options into effect

Returns:

  • (String)

    tag dump as a String. tag.bytes represents the byte array



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/id3taginator/id3v2_tag.rb', line 173

def to_bytes
  # add up frame size and unsyc if necessary
  frames_payload = ''
  @frames.each do |frame|
    frames_payload += frame.to_bytes
  end

  frames_payload += "\x00" * @options.padding_bytes if @options.padding_bytes.positive?
  frames_payload = Util::SyncUtil.add_synchronization(frames_payload) if unsynchronized?
  frame_size = frames_payload.size

  res = 'ID3'
  res += @major_version.chr
  res += @minor_version.chr
  res += @flags.to_bytes
  res += Util::MathUtil.from_32_synchsafe_integer(frame_size)
  res += frames_payload

  if @flags&.footer?
    res = '3DI'
    res += @major_version.chr
    res += @minor_version.chr
    res += @flags.to_bytes
    res += Util::MathUtil.from_32_synchsafe_integer(frame_size)
  end

  res
end

#total_tag_sizeInteger

returns the number of bytes of the total tag, including header and footer

Returns:

  • (Integer)

    the total tag size in bytes



113
114
115
# File 'lib/id3taginator/id3v2_tag.rb', line 113

def total_tag_size
  @header_size + @tag_size + (@flags&.footer? ? 10 : 0)
end

#unsynchronized=(enabled = true) ⇒ Object

sets the tag synchronized or unsynchronized. Should be false, only required for very old player

Parameters:

  • enabled (Boolean) (defaults to: true)

    sets unsynchronized enabled or disabled



151
152
153
# File 'lib/id3taginator/id3v2_tag.rb', line 151

def unsynchronized=(enabled = true)
  @flags.unsynchronized = enabled
end

#unsynchronized?Boolean

determined if the tag is unsynchronized

Returns:

  • (Boolean)

    true if unsynchronized, else false



144
145
146
# File 'lib/id3taginator/id3v2_tag.rb', line 144

def unsynchronized?
  @flags.unsynchronized?
end

#versionString

gets the version of this id3tag entity

Returns:

  • (String)

    returns the version in the form 2.x.y



106
107
108
# File 'lib/id3taginator/id3v2_tag.rb', line 106

def version
  "2.#{@major_version}.#{@minor_version}"
end