wahwah 1.0.0 → 1.3.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.
@@ -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