wahwah 0.1.0.pre.test → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +8 -0
- data/.travis.yml +5 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +22 -0
- data/README.md +35 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/wahwah.rb +3 -74
- data/lib/wahwah/version.rb +2 -4
- data/wahwah.gemspec +27 -0
- metadata +25 -96
- data/LICENSE +0 -21
- data/lib/wahwah/asf/object.rb +0 -39
- data/lib/wahwah/asf_tag.rb +0 -220
- data/lib/wahwah/errors.rb +0 -6
- data/lib/wahwah/flac/block.rb +0 -57
- data/lib/wahwah/flac/streaminfo_block.rb +0 -51
- data/lib/wahwah/flac_tag.rb +0 -84
- data/lib/wahwah/helper.rb +0 -37
- data/lib/wahwah/id3/comment_frame_body.rb +0 -21
- data/lib/wahwah/id3/frame.rb +0 -180
- data/lib/wahwah/id3/frame_body.rb +0 -36
- data/lib/wahwah/id3/genre_frame_body.rb +0 -15
- data/lib/wahwah/id3/image_frame_body.rb +0 -60
- data/lib/wahwah/id3/text_frame_body.rb +0 -16
- data/lib/wahwah/id3/v1.rb +0 -96
- data/lib/wahwah/id3/v2.rb +0 -60
- data/lib/wahwah/id3/v2_header.rb +0 -53
- data/lib/wahwah/mp3/mpeg_frame_header.rb +0 -141
- data/lib/wahwah/mp3/vbri_header.rb +0 -47
- data/lib/wahwah/mp3/xing_header.rb +0 -45
- data/lib/wahwah/mp3_tag.rb +0 -110
- data/lib/wahwah/mp4/atom.rb +0 -105
- data/lib/wahwah/mp4_tag.rb +0 -126
- data/lib/wahwah/ogg/flac_tag.rb +0 -37
- data/lib/wahwah/ogg/opus_tag.rb +0 -33
- data/lib/wahwah/ogg/packets.rb +0 -41
- data/lib/wahwah/ogg/page.rb +0 -121
- data/lib/wahwah/ogg/pages.rb +0 -24
- data/lib/wahwah/ogg/vorbis_comment.rb +0 -51
- data/lib/wahwah/ogg/vorbis_tag.rb +0 -35
- data/lib/wahwah/ogg_tag.rb +0 -66
- data/lib/wahwah/riff/chunk.rb +0 -54
- data/lib/wahwah/riff_tag.rb +0 -140
- data/lib/wahwah/tag.rb +0 -59
- data/lib/wahwah/tag_delegate.rb +0 -16
data/lib/wahwah/helper.rb
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module WahWah
|
4
|
-
module Helper
|
5
|
-
def self.encode_to_utf8(string, source_encoding: '')
|
6
|
-
encoded_string = source_encoding.empty? ?
|
7
|
-
string.force_encoding('utf-8') :
|
8
|
-
string.encode('utf-8', source_encoding, invalid: :replace, undef: :replace, replace: '')
|
9
|
-
|
10
|
-
encoded_string.valid_encoding? ? encoded_string.strip : ''
|
11
|
-
end
|
12
|
-
|
13
|
-
# ID3 size is encoded with four bytes where may the most significant
|
14
|
-
# bit (bit 7) is set to zero in every byte,
|
15
|
-
# making a total of 28 bits. The zeroed bits are ignored
|
16
|
-
def self.id3_size_caculate(bits_string, has_zero_bit: true)
|
17
|
-
if has_zero_bit
|
18
|
-
bits_string.scan(/.{8}/).map { |byte_string| byte_string[1..-1] }.join.to_i(2)
|
19
|
-
else
|
20
|
-
bits_string.to_i(2)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.split_with_terminator(string, terminator_size)
|
25
|
-
string.split(Regexp.new(('\x00' * terminator_size).b), 2)
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.file_format(file_path)
|
29
|
-
File.extname(file_path).downcase.delete('.')
|
30
|
-
end
|
31
|
-
|
32
|
-
def self.byte_string_to_guid(byte_string)
|
33
|
-
guid = byte_string.unpack('NnnA*').pack('VvvA*').unpack('H*').first
|
34
|
-
[guid[0..7], guid[8..11], guid[12..15], guid[16..19], guid[20..-1]].join('-').upcase
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module WahWah
|
4
|
-
module ID3
|
5
|
-
class CommentFrameBody < FrameBody
|
6
|
-
# Comment frame body structure:
|
7
|
-
#
|
8
|
-
# Text encoding $xx
|
9
|
-
# Language $xx xx xx
|
10
|
-
# Short content description <textstring> $00 (00)
|
11
|
-
# The actual text <textstring>
|
12
|
-
def parse
|
13
|
-
encoding_id, _language, reset_content = @content.unpack('CA3a*')
|
14
|
-
encoding = ENCODING_MAPPING[encoding_id]
|
15
|
-
_description, comment_text = Helper.split_with_terminator(reset_content, ENCODING_TERMINATOR_SIZE[encoding])
|
16
|
-
|
17
|
-
@value = Helper.encode_to_utf8(comment_text, source_encoding: encoding)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
data/lib/wahwah/id3/frame.rb
DELETED
@@ -1,180 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'zlib'
|
4
|
-
|
5
|
-
module WahWah
|
6
|
-
module ID3
|
7
|
-
class Frame
|
8
|
-
ID_MAPPING = {
|
9
|
-
# ID3v2.2 frame id
|
10
|
-
COM: :comment,
|
11
|
-
TRK: :track,
|
12
|
-
TYE: :year,
|
13
|
-
TAL: :album,
|
14
|
-
TP1: :artist,
|
15
|
-
TT2: :title,
|
16
|
-
TCO: :genre,
|
17
|
-
TPA: :disc,
|
18
|
-
TP2: :albumartist,
|
19
|
-
TCM: :composer,
|
20
|
-
PIC: :image,
|
21
|
-
|
22
|
-
# ID3v2.3 and ID3v2.4 frame id
|
23
|
-
COMM: :comment,
|
24
|
-
TRCK: :track,
|
25
|
-
TYER: :year,
|
26
|
-
TALB: :album,
|
27
|
-
TPE1: :artist,
|
28
|
-
TIT2: :title,
|
29
|
-
TCON: :genre,
|
30
|
-
TPOS: :disc,
|
31
|
-
TPE2: :albumartist,
|
32
|
-
TCOM: :composer,
|
33
|
-
APIC: :image,
|
34
|
-
|
35
|
-
# ID3v2.4 use TDRC replace TYER
|
36
|
-
TDRC: :year
|
37
|
-
}
|
38
|
-
|
39
|
-
# ID3v2.3 frame flags field is defined as follows.
|
40
|
-
#
|
41
|
-
# %abc00000 %ijk00000
|
42
|
-
#
|
43
|
-
# a - Tag alter preservation
|
44
|
-
# b - File alter preservation
|
45
|
-
# c - Read only
|
46
|
-
# i - Compression
|
47
|
-
# j - Encryption
|
48
|
-
# k - Grouping identity
|
49
|
-
V3_HEADER_FLAGS_INDICATIONS = Array.new(16).tap do |array|
|
50
|
-
array[0] = :tag_alter_preservation
|
51
|
-
array[1] = :file_alter_preservation
|
52
|
-
array[2] = :read_only
|
53
|
-
array[8] = :compression
|
54
|
-
array[9] = :encryption
|
55
|
-
array[10] = :grouping_identity
|
56
|
-
end
|
57
|
-
|
58
|
-
# ID3v2.4 frame flags field is defined as follows.
|
59
|
-
#
|
60
|
-
# %0abc0000 %0h00kmnp
|
61
|
-
#
|
62
|
-
# a - Tag alter preservation
|
63
|
-
# b - File alter preservation
|
64
|
-
# c - Read only
|
65
|
-
# h - Grouping identity
|
66
|
-
# k - Compression
|
67
|
-
# m - Encryption
|
68
|
-
# n - Unsynchronisation
|
69
|
-
# p - Data length indicator
|
70
|
-
V4_HEADER_FLAGS_INDICATIONS = Array.new(16).tap do |array|
|
71
|
-
array[1] = :tag_alter_preservation
|
72
|
-
array[2] = :file_alter_preservation
|
73
|
-
array[3] = :read_only
|
74
|
-
array[9] = :grouping_identity
|
75
|
-
array[12] = :compression
|
76
|
-
array[13] = :encryption
|
77
|
-
array[14] = :unsynchronisation
|
78
|
-
array[15] = :data_length_indicator
|
79
|
-
end
|
80
|
-
|
81
|
-
attr_reader :name, :value
|
82
|
-
|
83
|
-
def initialize(file_io, version)
|
84
|
-
@file_io = file_io
|
85
|
-
@version = version
|
86
|
-
|
87
|
-
parse_frame_header
|
88
|
-
|
89
|
-
# In ID3v2.3 when frame is compressed using zlib
|
90
|
-
# with 4 bytes for 'decompressed size' appended to the frame header.
|
91
|
-
#
|
92
|
-
# In ID3v2.4 A 'Data Length Indicator' byte MUST be included in the frame
|
93
|
-
# when frame is compressed, and 'Data Length Indicator'represented as a 32 bit
|
94
|
-
# synchsafe integer
|
95
|
-
#
|
96
|
-
# So skip those 4 byte.
|
97
|
-
if compressed? || data_length_indicator?
|
98
|
-
@file_io.seek(4, IO::SEEK_CUR)
|
99
|
-
@size = @size - 4
|
100
|
-
end
|
101
|
-
|
102
|
-
parse_body
|
103
|
-
end
|
104
|
-
|
105
|
-
def valid?
|
106
|
-
@size > 0 && !@name.nil?
|
107
|
-
end
|
108
|
-
|
109
|
-
def compressed?
|
110
|
-
@flags.include? :compression
|
111
|
-
end
|
112
|
-
|
113
|
-
def data_length_indicator?
|
114
|
-
@flags.include? :data_length_indicator
|
115
|
-
end
|
116
|
-
|
117
|
-
|
118
|
-
private
|
119
|
-
# ID3v2.2 frame header structure:
|
120
|
-
#
|
121
|
-
# Frame ID $xx xx xx(tree characters)
|
122
|
-
# Size 3 * %xxxxxxxx
|
123
|
-
#
|
124
|
-
# ID3v2.3 frame header structure:
|
125
|
-
#
|
126
|
-
# Frame ID $xx xx xx xx (four characters)
|
127
|
-
# Size 4 * %xxxxxxxx
|
128
|
-
# Flags $xx xx
|
129
|
-
#
|
130
|
-
# ID3v2.4 frame header structure:
|
131
|
-
#
|
132
|
-
# Frame ID $xx xx xx xx (four characters)
|
133
|
-
# Size 4 * %0xxxxxxx
|
134
|
-
# Flags $xx xx
|
135
|
-
def parse_frame_header
|
136
|
-
header_size = @version == 2 ? 6 : 10
|
137
|
-
header_formate = @version == 2 ? 'A3B24' : 'A4B32B16'
|
138
|
-
id, size_bits, flags_bits = @file_io.read(header_size).unpack(header_formate)
|
139
|
-
|
140
|
-
@name = ID_MAPPING[id.to_sym]
|
141
|
-
@size = Helper.id3_size_caculate(size_bits, has_zero_bit: @version == 4)
|
142
|
-
@flags = parse_flags(flags_bits)
|
143
|
-
end
|
144
|
-
|
145
|
-
def parse_flags(flags_bits)
|
146
|
-
return [] if flags_bits.nil?
|
147
|
-
|
148
|
-
frame_flags_indications = @version == 4 ?
|
149
|
-
V4_HEADER_FLAGS_INDICATIONS :
|
150
|
-
V3_HEADER_FLAGS_INDICATIONS
|
151
|
-
|
152
|
-
flags_bits.split('').map.with_index do |flag_bit, index|
|
153
|
-
frame_flags_indications[index] if flag_bit == '1'
|
154
|
-
end.compact
|
155
|
-
end
|
156
|
-
|
157
|
-
def parse_body
|
158
|
-
return unless @size > 0
|
159
|
-
(@file_io.seek(@size, IO::SEEK_CUR); return) if @name.nil?
|
160
|
-
|
161
|
-
content = compressed? ? Zlib.inflate(@file_io.read(@size)) : @file_io.read(@size)
|
162
|
-
frame_body = frame_body_class.new(content, @version)
|
163
|
-
@value = frame_body.value
|
164
|
-
end
|
165
|
-
|
166
|
-
def frame_body_class
|
167
|
-
case @name
|
168
|
-
when :comment
|
169
|
-
CommentFrameBody
|
170
|
-
when :genre
|
171
|
-
GenreFrameBody
|
172
|
-
when :image
|
173
|
-
ImageFrameBody
|
174
|
-
else
|
175
|
-
TextFrameBody
|
176
|
-
end
|
177
|
-
end
|
178
|
-
end
|
179
|
-
end
|
180
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module WahWah
|
4
|
-
module ID3
|
5
|
-
class FrameBody
|
6
|
-
# Textual frames are marked with an encoding byte.
|
7
|
-
#
|
8
|
-
# $00 ISO-8859-1 [ISO-8859-1]. Terminated with $00.
|
9
|
-
# $01 UTF-16 [UTF-16] encoded Unicode [UNICODE] with BOM.
|
10
|
-
# $02 UTF-16BE [UTF-16] encoded Unicode [UNICODE] without BOM.
|
11
|
-
# $03 UTF-8 [UTF-8] encoded Unicode [UNICODE].
|
12
|
-
ENCODING_MAPPING = %w(ISO-8859-1 UTF-16 UTF-16BE UTF-8)
|
13
|
-
|
14
|
-
ENCODING_TERMINATOR_SIZE = {
|
15
|
-
'ISO-8859-1' => 1,
|
16
|
-
'UTF-16' => 2,
|
17
|
-
'UTF-16BE' => 2,
|
18
|
-
'UTF-8' => 1
|
19
|
-
}
|
20
|
-
|
21
|
-
|
22
|
-
attr_reader :value
|
23
|
-
|
24
|
-
def initialize(content, version)
|
25
|
-
@content = content
|
26
|
-
@version = version
|
27
|
-
|
28
|
-
parse
|
29
|
-
end
|
30
|
-
|
31
|
-
def parse
|
32
|
-
raise WahWahNotImplementedError, 'The parse method is not implemented'
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module WahWah
|
4
|
-
module ID3
|
5
|
-
class GenreFrameBody < TextFrameBody
|
6
|
-
def parse
|
7
|
-
super
|
8
|
-
|
9
|
-
# If value is numeric value, or contain numeric value in parens
|
10
|
-
# can use as index for ID3v1 genre list
|
11
|
-
@value = ID3::V1::GENRES[$1.to_i] if @value =~ /^\((\d+)\)$/ || @value =~ /^(\d+)$/
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
@@ -1,60 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module WahWah
|
4
|
-
module ID3
|
5
|
-
class ImageFrameBody < FrameBody
|
6
|
-
TYPES = %i(
|
7
|
-
other
|
8
|
-
file_icon
|
9
|
-
other_file_icon
|
10
|
-
cover_front
|
11
|
-
cover_back
|
12
|
-
leaflet
|
13
|
-
media
|
14
|
-
lead_artist
|
15
|
-
artist
|
16
|
-
conductor
|
17
|
-
band
|
18
|
-
composer
|
19
|
-
lyricist
|
20
|
-
recording_location
|
21
|
-
during_recording
|
22
|
-
during_performance
|
23
|
-
movie_screen_capture
|
24
|
-
bright_coloured_fish
|
25
|
-
illustration
|
26
|
-
band_logotype
|
27
|
-
publisher_logotype
|
28
|
-
)
|
29
|
-
|
30
|
-
def mime_type
|
31
|
-
mime_type = @mime_type.downcase.yield_self { |type| type == 'jpg' ? 'jpeg' : type }
|
32
|
-
@version > 2 ? mime_type : "image/#{mime_type}"
|
33
|
-
end
|
34
|
-
|
35
|
-
# ID3v2.2 image frame structure:
|
36
|
-
#
|
37
|
-
# Text encoding $xx
|
38
|
-
# Image format $xx xx xx
|
39
|
-
# Picture type $xx
|
40
|
-
# Description <text string according to encoding> $00 (00)
|
41
|
-
# Picture data <binary data>
|
42
|
-
#
|
43
|
-
# ID3v2.3 and ID3v2.4 image frame structure:
|
44
|
-
#
|
45
|
-
# Text encoding $xx
|
46
|
-
# MIME type <text string> $00
|
47
|
-
# Picture type $xx
|
48
|
-
# Description <text string according to encoding> $00 (00)
|
49
|
-
# Picture data <binary data>
|
50
|
-
def parse
|
51
|
-
frame_format = @version > 2 ? 'CZ*Ca*' : 'Ca3Ca*'
|
52
|
-
encoding_id, @mime_type, type_index, reset_content = @content.unpack(frame_format)
|
53
|
-
encoding = ENCODING_MAPPING[encoding_id]
|
54
|
-
_description, data = Helper.split_with_terminator(reset_content, ENCODING_TERMINATOR_SIZE[encoding])
|
55
|
-
|
56
|
-
@value = { data: data, mime_type: mime_type, type: TYPES[type_index] }
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module WahWah
|
4
|
-
module ID3
|
5
|
-
class TextFrameBody < FrameBody
|
6
|
-
# Text frame boby structure:
|
7
|
-
#
|
8
|
-
# Text encoding $xx
|
9
|
-
# Information <text string according to encoding>
|
10
|
-
def parse
|
11
|
-
encoding_id, text = @content.unpack('Ca*')
|
12
|
-
@value = Helper.encode_to_utf8(text, source_encoding: ENCODING_MAPPING[encoding_id])
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
data/lib/wahwah/id3/v1.rb
DELETED
@@ -1,96 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module WahWah
|
4
|
-
module ID3
|
5
|
-
class V1 < Tag
|
6
|
-
TAG_SIZE = 128
|
7
|
-
TAG_ID = 'TAG'
|
8
|
-
DEFAULT_ENCODING = 'iso-8859-1'
|
9
|
-
GENRES = [
|
10
|
-
# Standard Genres
|
11
|
-
'Blues', 'Classic Rock', 'Country', 'Dance', 'Disco', 'Funk', 'Grunge',
|
12
|
-
'Hip-Hop', 'Jazz', 'Metal', 'New Age', 'Oldies', 'Other', 'Pop',
|
13
|
-
'R&B', 'Rap', 'Reggae', 'Rock', 'Techno', 'Industrial', 'Alternative',
|
14
|
-
'Ska', 'Death Metal', 'Pranks', 'Soundtrack', 'Euro-Techno', 'Ambient', 'Trip-Hop',
|
15
|
-
'Vocal', 'Jazz+Funk', 'Fusion', 'Trance', 'Classical', 'Instrumental', 'Acid',
|
16
|
-
'House', 'Game', 'Sound Clip', 'Gospel', 'Noise', 'AlternRock', 'Bass',
|
17
|
-
'Soul', 'Punk', 'Space', 'Meditative', 'Instrumental Pop', 'Instrumental Rock', 'Ethnic',
|
18
|
-
'Gothic', 'Darkwave', 'Techno-Industrial', 'Electronic', 'Pop-Folk', 'Eurodance', 'Dream',
|
19
|
-
'Southern Rock', 'Comedy', 'Cult', 'Gangsta', 'Top 40', 'Christian Rap', 'Pop/Funk',
|
20
|
-
'Jungle', 'Native American', 'Cabaret', 'New Wave', 'Psychadelic', 'Rave', 'Showtunes',
|
21
|
-
'Trailer', 'Lo-Fi', 'Tribal', 'Acid Punk', 'Acid Jazz', 'Polka', 'Retro',
|
22
|
-
'Musical', 'Rock & Roll', 'Hard Rock',
|
23
|
-
|
24
|
-
# Winamp Extended Genres
|
25
|
-
'Folk', 'Folk-Rock', 'National Folk', 'Swing', 'Fast Fusion', 'Bebob', 'Latin',
|
26
|
-
'Revival', 'Celtic', 'Bluegrass', 'Avantgarde', 'Gothic Rock', 'Progressive Rock', 'Psychedelic Rock',
|
27
|
-
'Symphonic Rock', 'Slow Rock', 'Big Band', 'Chorus', 'Easy Listening', 'Acoustic', 'Humour',
|
28
|
-
'Speech', 'Chanson', 'Opera', 'Chamber Music', 'Sonata', 'Symphony', 'Booty Bass',
|
29
|
-
'Primus', 'Porn Groove', 'Satire', 'Slow Jam', 'Club', 'Tango', 'Samba',
|
30
|
-
'Folklore', 'Ballad', 'Power Ballad', 'Rhythmic Soul', 'Freestyle', 'Duet', 'Punk Rock',
|
31
|
-
'Drum Solo', 'A capella', 'Euro-House', 'Dance Hall', 'Goa', 'Drum & Bass', 'Club-House',
|
32
|
-
'Hardcore Techno', 'Terror', 'Indie', 'BritPop', 'Negerpunk', 'Polsk Punk', 'Beat',
|
33
|
-
'Christian Gangsta Rap', 'Heavy Metal', 'Black Metal', 'Contemporary Christian', 'Christian Rock',
|
34
|
-
|
35
|
-
# Added on WinAmp 1.91
|
36
|
-
'Merengue', 'Salsa', 'Thrash Metal', 'Anime', 'Jpop', 'Synthpop',
|
37
|
-
|
38
|
-
# Added on WinAmp 5.6
|
39
|
-
'Abstract', 'Art Rock', 'Baroque', 'Bhangra', 'Big Beat', 'Breakbeat', 'Chillout',
|
40
|
-
'Downtempo', 'Dub', 'EBM', 'Eclectic', 'Electro', 'Electroclash', 'Emo',
|
41
|
-
'Experimental', 'Garage', 'Illbient', 'Industro-Goth', 'Jam Band', 'Krautrock', 'Leftfield',
|
42
|
-
'Lounge', 'Math Rock', 'New Romantic', 'Nu-Breakz', 'Post-Punk', 'Post-Rock', 'Psytrance',
|
43
|
-
'Shoegaze', 'Space Rock', 'Trop Rock', 'World Music', 'Neoclassical', 'Audiobook', 'Audio Theatre',
|
44
|
-
'Neue Deutsche Welle', 'Podcast', 'Indie Rock', 'G-Funk', 'Dubstep', 'Garage Rock', 'Psybient'
|
45
|
-
]
|
46
|
-
|
47
|
-
def size
|
48
|
-
TAG_SIZE
|
49
|
-
end
|
50
|
-
|
51
|
-
def version
|
52
|
-
'v1'
|
53
|
-
end
|
54
|
-
|
55
|
-
def valid?
|
56
|
-
@id == TAG_ID
|
57
|
-
end
|
58
|
-
|
59
|
-
private
|
60
|
-
# For ID3v1 info, see here https://en.wikipedia.org/wiki/ID3#ID3v1
|
61
|
-
#
|
62
|
-
# header 3 "TAG"
|
63
|
-
# title 30 30 characters of the title
|
64
|
-
# artist 30 30 characters of the artist name
|
65
|
-
# album 30 30 characters of the album name
|
66
|
-
# year 4 A four-digit year
|
67
|
-
# comment 28 or 30 The comment.
|
68
|
-
# zero-byte 1 If a track number is stored, this byte contains a binary 0.
|
69
|
-
# track 1 The number of the track on the album, or 0. Invalid, if previous byte is not a binary 0.
|
70
|
-
# genre 1 Index in a list of genres, or 255
|
71
|
-
def parse
|
72
|
-
return unless @file_io.size >= TAG_SIZE
|
73
|
-
|
74
|
-
@file_io.seek(-TAG_SIZE, IO::SEEK_END)
|
75
|
-
@id = Helper.encode_to_utf8(@file_io.read(3), source_encoding: DEFAULT_ENCODING)
|
76
|
-
|
77
|
-
return unless valid?
|
78
|
-
|
79
|
-
@title = Helper.encode_to_utf8(@file_io.read(30), source_encoding: DEFAULT_ENCODING)
|
80
|
-
@artist = Helper.encode_to_utf8(@file_io.read(30), source_encoding: DEFAULT_ENCODING)
|
81
|
-
@album = Helper.encode_to_utf8(@file_io.read(30), source_encoding: DEFAULT_ENCODING)
|
82
|
-
@year = Helper.encode_to_utf8(@file_io.read(4), source_encoding: DEFAULT_ENCODING)
|
83
|
-
|
84
|
-
comment = @file_io.read(30)
|
85
|
-
|
86
|
-
if comment.getbyte(-2) == 0
|
87
|
-
@track = comment.getbyte(-1)
|
88
|
-
comment = comment.byteslice(0..-3)
|
89
|
-
end
|
90
|
-
|
91
|
-
@comments.push(Helper.encode_to_utf8(comment, source_encoding: DEFAULT_ENCODING))
|
92
|
-
@genre = GENRES[@file_io.getbyte] || ''
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|