wahwah 1.0.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,80 +5,82 @@ module WahWah
5
5
  include Ogg::VorbisComment
6
6
  include Flac::StreaminfoBlock
7
7
 
8
- TAG_ID = 'fLaC'
8
+ TAG_ID = "fLaC"
9
9
 
10
10
  private
11
- # FLAC structure:
12
- #
13
- # The four byte string "fLaC"
14
- # The STREAMINFO metadata block
15
- # Zero or more other metadata blocks
16
- # One or more audio frames
17
- def parse
18
- # Flac file maybe contain ID3 header on the start, so skip it if exists
19
- id3_header = ID3::V2Header.new(@file_io)
20
- id3_header.valid? ? @file_io.seek(id3_header.size) : @file_io.rewind
21
11
 
22
- return if @file_io.read(4) != TAG_ID
12
+ # FLAC structure:
13
+ #
14
+ # The four byte string "fLaC"
15
+ # The STREAMINFO metadata block
16
+ # Zero or more other metadata blocks
17
+ # One or more audio frames
18
+ def parse
19
+ # Flac file maybe contain ID3 header on the start, so skip it if exists
20
+ id3_header = ID3::V2Header.new(@file_io)
21
+ id3_header.valid? ? @file_io.seek(id3_header.size) : @file_io.rewind
23
22
 
24
- loop do
25
- block = Flac::Block.new(@file_io)
26
- parse_block(block)
23
+ return if @file_io.read(4) != TAG_ID
27
24
 
28
- break if block.is_last? || @file_io.eof?
29
- end
25
+ loop do
26
+ block = Flac::Block.new(@file_io)
27
+ parse_block(block)
28
+
29
+ break if block.is_last? || @file_io.eof?
30
30
  end
31
+ end
31
32
 
32
- def parse_block(block)
33
- return unless block.valid?
33
+ def parse_block(block)
34
+ return unless block.valid?
34
35
 
35
- case block.type
36
- when 'STREAMINFO'
37
- parse_streaminfo_block(block.data)
38
- when 'VORBIS_COMMENT'
39
- parse_vorbis_comment(block.data)
40
- when 'PICTURE'
41
- parse_picture_block(block.data)
42
- else
43
- @file_io.seek(block.size, IO::SEEK_CUR)
44
- end
36
+ case block.type
37
+ when "STREAMINFO"
38
+ parse_streaminfo_block(block.data)
39
+ when "VORBIS_COMMENT"
40
+ parse_vorbis_comment(block.data)
41
+ when "PICTURE"
42
+ @images_data.push(block)
43
+ block.skip
44
+ else
45
+ block.skip
45
46
  end
47
+ end
46
48
 
47
- # PICTURE block data structure:
48
- #
49
- # Length(bit) Meaning
50
- #
51
- # 32 The picture type according to the ID3v2 APIC frame:
52
- #
53
- # 32 The length of the MIME type string in bytes.
54
- #
55
- # n*8 The MIME type string.
56
- #
57
- # 32 The length of the description string in bytes.
58
- #
59
- # n*8 The description of the picture, in UTF-8.
60
- #
61
- # 32 The width of the picture in pixels.
62
- #
63
- # 32 The height of the picture in pixels.
64
- #
65
- # 32 The color depth of the picture in bits-per-pixel.
66
- #
67
- # 32 For indexed-color pictures (e.g. GIF), the number of colors used, or 0 for non-indexed pictures.
68
- #
69
- # 32 The length of the picture data in bytes.
70
- #
71
- # n*8 The binary picture data.
72
- def parse_picture_block(block_data)
73
- block_content = StringIO.new(block_data)
49
+ # PICTURE block data structure:
50
+ #
51
+ # Length(bit) Meaning
52
+ #
53
+ # 32 The picture type according to the ID3v2 APIC frame:
54
+ #
55
+ # 32 The length of the MIME type string in bytes.
56
+ #
57
+ # n*8 The MIME type string.
58
+ #
59
+ # 32 The length of the description string in bytes.
60
+ #
61
+ # n*8 The description of the picture, in UTF-8.
62
+ #
63
+ # 32 The width of the picture in pixels.
64
+ #
65
+ # 32 The height of the picture in pixels.
66
+ #
67
+ # 32 The color depth of the picture in bits-per-pixel.
68
+ #
69
+ # 32 For indexed-color pictures (e.g. GIF), the number of colors used, or 0 for non-indexed pictures.
70
+ #
71
+ # 32 The length of the picture data in bytes.
72
+ #
73
+ # n*8 The binary picture data.
74
+ def parse_image_data(picture_block)
75
+ block_content = StringIO.new(picture_block.data)
74
76
 
75
- type_index, mime_type_length = block_content.read(8).unpack('NN')
76
- mime_type = Helper.encode_to_utf8(block_content.read(mime_type_length))
77
- description_length = block_content.read(4).unpack('N').first
78
- data_length = block_content.read(description_length + 20).unpack("#{'x' * (description_length + 16)}N").first
79
- data = block_content.read(data_length)
77
+ type_index, mime_type_length = block_content.read(8).unpack("NN")
78
+ mime_type = Helper.encode_to_utf8(block_content.read(mime_type_length))
79
+ description_length = block_content.read(4).unpack1("N")
80
+ data_length = block_content.read(description_length + 20).unpack1("#{"x" * (description_length + 16)}N")
81
+ data = block_content.read(data_length)
80
82
 
81
- @images.push({ data: data, mime_type: mime_type, type: ID3::ImageFrameBody::TYPES[type_index] })
82
- end
83
+ {data: data, mime_type: mime_type, type: ID3::ImageFrameBody::TYPES[type_index]}
84
+ end
83
85
  end
84
86
  end
data/lib/wahwah/helper.rb CHANGED
@@ -2,12 +2,12 @@
2
2
 
3
3
  module WahWah
4
4
  module Helper
5
- def self.encode_to_utf8(string, source_encoding: '')
5
+ def self.encode_to_utf8(string, source_encoding: "")
6
6
  encoded_string = source_encoding.empty? ?
7
- string.force_encoding('utf-8') :
8
- string.encode('utf-8', source_encoding, invalid: :replace, undef: :replace, replace: '')
7
+ string.force_encoding("utf-8") :
8
+ string.encode("utf-8", source_encoding, invalid: :replace, undef: :replace, replace: "")
9
9
 
10
- encoded_string.valid_encoding? ? encoded_string.strip : ''
10
+ encoded_string.valid_encoding? ? encoded_string.strip : ""
11
11
  end
12
12
 
13
13
  # ID3 size is encoded with four bytes where may the most significant
@@ -15,7 +15,7 @@ module WahWah
15
15
  # making a total of 28 bits. The zeroed bits are ignored
16
16
  def self.id3_size_caculate(bits_string, has_zero_bit: true)
17
17
  if has_zero_bit
18
- bits_string.scan(/.{8}/).map { |byte_string| byte_string[1..-1] }.join.to_i(2)
18
+ bits_string.scan(/.{8}/).map { |byte_string| byte_string[1..] }.join.to_i(2)
19
19
  else
20
20
  bits_string.to_i(2)
21
21
  end
@@ -26,12 +26,12 @@ module WahWah
26
26
  end
27
27
 
28
28
  def self.file_format(file_path)
29
- File.extname(file_path).downcase.delete('.')
29
+ File.extname(file_path).downcase.delete(".")
30
30
  end
31
31
 
32
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
33
+ guid = byte_string.unpack("NnnA*").pack("VvvA*").unpack1("H*")
34
+ [guid[0..7], guid[8..11], guid[12..15], guid[16..19], guid[20..]].join("-").upcase
35
35
  end
36
36
  end
37
37
  end
@@ -10,7 +10,7 @@ module WahWah
10
10
  # Short content description <textstring> $00 (00)
11
11
  # The actual text <textstring>
12
12
  def parse
13
- encoding_id, _language, reset_content = @content.unpack('CA3a*')
13
+ encoding_id, _language, reset_content = @content.unpack("CA3a*")
14
14
  encoding = ENCODING_MAPPING[encoding_id]
15
15
  _description, comment_text = Helper.split_with_terminator(reset_content, ENCODING_TERMINATOR_SIZE[encoding])
16
16
 
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'zlib'
4
-
5
3
  module WahWah
6
4
  module ID3
7
5
  class Frame
6
+ prepend LazyRead
7
+
8
8
  ID_MAPPING = {
9
9
  # ID3v2.2 frame id
10
10
  COM: :comment,
@@ -78,10 +78,9 @@ module WahWah
78
78
  array[15] = :data_length_indicator
79
79
  end
80
80
 
81
- attr_reader :name, :value
81
+ attr_reader :name
82
82
 
83
- def initialize(file_io, version)
84
- @file_io = file_io
83
+ def initialize(version)
85
84
  @version = version
86
85
 
87
86
  parse_frame_header
@@ -96,10 +95,8 @@ module WahWah
96
95
  # So skip those 4 byte.
97
96
  if compressed? || data_length_indicator?
98
97
  @file_io.seek(4, IO::SEEK_CUR)
99
- @size = @size - 4
98
+ @size -= 4
100
99
  end
101
-
102
- parse_body
103
100
  end
104
101
 
105
102
  def valid?
@@ -114,67 +111,66 @@ module WahWah
114
111
  @flags.include? :data_length_indicator
115
112
  end
116
113
 
114
+ def value
115
+ return unless @size > 0
117
116
 
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
117
+ content = compressed? ? Zlib.inflate(data) : data
118
+ frame_body = frame_body_class.new(content, @version)
119
+ frame_body.value
120
+ end
144
121
 
145
- def parse_flags(flags_bits)
146
- return [] if flags_bits.nil?
122
+ private
147
123
 
148
- frame_flags_indications = @version == 4 ?
149
- V4_HEADER_FLAGS_INDICATIONS :
150
- V3_HEADER_FLAGS_INDICATIONS
124
+ # ID3v2.2 frame header structure:
125
+ #
126
+ # Frame ID $xx xx xx(tree characters)
127
+ # Size 3 * %xxxxxxxx
128
+ #
129
+ # ID3v2.3 frame header structure:
130
+ #
131
+ # Frame ID $xx xx xx xx (four characters)
132
+ # Size 4 * %xxxxxxxx
133
+ # Flags $xx xx
134
+ #
135
+ # ID3v2.4 frame header structure:
136
+ #
137
+ # Frame ID $xx xx xx xx (four characters)
138
+ # Size 4 * %0xxxxxxx
139
+ # Flags $xx xx
140
+ def parse_frame_header
141
+ header_size = @version == 2 ? 6 : 10
142
+ header_formate = @version == 2 ? "A3B24" : "A4B32B16"
143
+ id, size_bits, flags_bits = @file_io.read(header_size).unpack(header_formate)
144
+
145
+ @name = ID_MAPPING[id.to_sym]
146
+ @size = Helper.id3_size_caculate(size_bits, has_zero_bit: @version == 4)
147
+ @flags = parse_flags(flags_bits)
148
+ end
151
149
 
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
150
+ def parse_flags(flags_bits)
151
+ return [] if flags_bits.nil?
156
152
 
157
- def parse_body
158
- return unless @size > 0
159
- (@file_io.seek(@size, IO::SEEK_CUR); return) if @name.nil?
153
+ frame_flags_indications = @version == 4 ?
154
+ V4_HEADER_FLAGS_INDICATIONS :
155
+ V3_HEADER_FLAGS_INDICATIONS
160
156
 
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
157
+ flags_bits.chars.map.with_index do |flag_bit, index|
158
+ frame_flags_indications[index] if flag_bit == "1"
159
+ end.compact
160
+ end
165
161
 
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
162
+ def frame_body_class
163
+ case @name
164
+ when :comment
165
+ CommentFrameBody
166
+ when :genre
167
+ GenreFrameBody
168
+ when :image
169
+ ImageFrameBody
170
+ else
171
+ TextFrameBody
177
172
  end
173
+ end
178
174
  end
179
175
  end
180
176
  end
@@ -9,16 +9,15 @@ module WahWah
9
9
  # $01 UTF-16 [UTF-16] encoded Unicode [UNICODE] with BOM.
10
10
  # $02 UTF-16BE [UTF-16] encoded Unicode [UNICODE] without BOM.
11
11
  # $03 UTF-8 [UTF-8] encoded Unicode [UNICODE].
12
- ENCODING_MAPPING = %w(ISO-8859-1 UTF-16 UTF-16BE UTF-8)
12
+ ENCODING_MAPPING = %w[ISO-8859-1 UTF-16 UTF-16BE UTF-8]
13
13
 
14
14
  ENCODING_TERMINATOR_SIZE = {
15
- 'ISO-8859-1' => 1,
16
- 'UTF-16' => 2,
17
- 'UTF-16BE' => 2,
18
- 'UTF-8' => 1
15
+ "ISO-8859-1" => 1,
16
+ "UTF-16" => 2,
17
+ "UTF-16BE" => 2,
18
+ "UTF-8" => 1
19
19
  }
20
20
 
21
-
22
21
  attr_reader :value
23
22
 
24
23
  def initialize(content, version)
@@ -29,7 +28,7 @@ module WahWah
29
28
  end
30
29
 
31
30
  def parse
32
- raise WahWahNotImplementedError, 'The parse method is not implemented'
31
+ raise WahWahNotImplementedError, "The parse method is not implemented"
33
32
  end
34
33
  end
35
34
  end
@@ -3,7 +3,7 @@
3
3
  module WahWah
4
4
  module ID3
5
5
  class ImageFrameBody < FrameBody
6
- TYPES = %i(
6
+ TYPES = %i[
7
7
  other
8
8
  file_icon
9
9
  other_file_icon
@@ -25,10 +25,10 @@ module WahWah
25
25
  illustration
26
26
  band_logotype
27
27
  publisher_logotype
28
- )
28
+ ]
29
29
 
30
30
  def mime_type
31
- mime_type = @mime_type.downcase.yield_self { |type| type == 'jpg' ? 'jpeg' : type }
31
+ mime_type = @mime_type.downcase.yield_self { |type| type == "jpg" ? "jpeg" : type }
32
32
  @version > 2 ? mime_type : "image/#{mime_type}"
33
33
  end
34
34
 
@@ -48,12 +48,12 @@ module WahWah
48
48
  # Description <text string according to encoding> $00 (00)
49
49
  # Picture data <binary data>
50
50
  def parse
51
- frame_format = @version > 2 ? 'CZ*Ca*' : 'Ca3Ca*'
51
+ frame_format = @version > 2 ? "CZ*Ca*" : "Ca3Ca*"
52
52
  encoding_id, @mime_type, type_index, reset_content = @content.unpack(frame_format)
53
53
  encoding = ENCODING_MAPPING[encoding_id]
54
54
  _description, data = Helper.split_with_terminator(reset_content, ENCODING_TERMINATOR_SIZE[encoding])
55
55
 
56
- @value = { data: data, mime_type: mime_type, type: TYPES[type_index] }
56
+ @value = {data: data, mime_type: mime_type, type: TYPES[type_index]}
57
57
  end
58
58
  end
59
59
  end
@@ -8,7 +8,7 @@ module WahWah
8
8
  # Text encoding $xx
9
9
  # Information <text string according to encoding>
10
10
  def parse
11
- encoding_id, text = @content.unpack('Ca*')
11
+ encoding_id, text = @content.unpack("Ca*")
12
12
  @value = Helper.encode_to_utf8(text, source_encoding: ENCODING_MAPPING[encoding_id])
13
13
  end
14
14
  end
data/lib/wahwah/id3/v1.rb CHANGED
@@ -4,44 +4,44 @@ module WahWah
4
4
  module ID3
5
5
  class V1 < Tag
6
6
  TAG_SIZE = 128
7
- TAG_ID = 'TAG'
8
- DEFAULT_ENCODING = 'iso-8859-1'
7
+ TAG_ID = "TAG"
8
+ DEFAULT_ENCODING = "iso-8859-1"
9
9
  GENRES = [
10
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',
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
23
 
24
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',
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
34
 
35
35
  # Added on WinAmp 1.91
36
- 'Merengue', 'Salsa', 'Thrash Metal', 'Anime', 'Jpop', 'Synthpop',
36
+ "Merengue", "Salsa", "Thrash Metal", "Anime", "Jpop", "Synthpop",
37
37
 
38
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'
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
45
  ]
46
46
 
47
47
  def size
@@ -49,7 +49,7 @@ module WahWah
49
49
  end
50
50
 
51
51
  def version
52
- 'v1'
52
+ "v1"
53
53
  end
54
54
 
55
55
  def valid?
@@ -57,40 +57,41 @@ module WahWah
57
57
  end
58
58
 
59
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
60
 
74
- @file_io.seek(-TAG_SIZE, IO::SEEK_END)
75
- @id = Helper.encode_to_utf8(@file_io.read(3), source_encoding: DEFAULT_ENCODING)
61
+ # For ID3v1 info, see here https://en.wikipedia.org/wiki/ID3#ID3v1
62
+ #
63
+ # header 3 "TAG"
64
+ # title 30 30 characters of the title
65
+ # artist 30 30 characters of the artist name
66
+ # album 30 30 characters of the album name
67
+ # year 4 A four-digit year
68
+ # comment 28 or 30 The comment.
69
+ # zero-byte 1 If a track number is stored, this byte contains a binary 0.
70
+ # track 1 The number of the track on the album, or 0. Invalid, if previous byte is not a binary 0.
71
+ # genre 1 Index in a list of genres, or 255
72
+ def parse
73
+ return unless @file_io.size >= TAG_SIZE
76
74
 
77
- return unless valid?
75
+ @file_io.seek(-TAG_SIZE, IO::SEEK_END)
76
+ @id = Helper.encode_to_utf8(@file_io.read(3), source_encoding: DEFAULT_ENCODING)
78
77
 
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)
78
+ return unless valid?
83
79
 
84
- comment = @file_io.read(30)
80
+ @title = Helper.encode_to_utf8(@file_io.read(30), source_encoding: DEFAULT_ENCODING)
81
+ @artist = Helper.encode_to_utf8(@file_io.read(30), source_encoding: DEFAULT_ENCODING)
82
+ @album = Helper.encode_to_utf8(@file_io.read(30), source_encoding: DEFAULT_ENCODING)
83
+ @year = Helper.encode_to_utf8(@file_io.read(4), source_encoding: DEFAULT_ENCODING)
85
84
 
86
- if comment.getbyte(-2) == 0
87
- @track = comment.getbyte(-1)
88
- comment = comment.byteslice(0..-3)
89
- end
85
+ comment = @file_io.read(30)
90
86
 
91
- @comments.push(Helper.encode_to_utf8(comment, source_encoding: DEFAULT_ENCODING))
92
- @genre = GENRES[@file_io.getbyte] || ''
87
+ if comment.getbyte(-2) == 0
88
+ @track = comment.getbyte(-1)
89
+ comment = comment.byteslice(0..-3)
93
90
  end
91
+
92
+ @comments.push(Helper.encode_to_utf8(comment, source_encoding: DEFAULT_ENCODING))
93
+ @genre = GENRES[@file_io.getbyte] || ""
94
+ end
94
95
  end
95
96
  end
96
97
  end