id3tag 0.8.0 → 0.9.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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -46
  3. data/.travis.yml +6 -5
  4. data/id3tag.gemspec +8 -8
  5. data/lib/id3tag/audio_file.rb +24 -6
  6. data/lib/id3tag/id3_v2_tag_header.rb +4 -4
  7. data/lib/id3tag/number_util.rb +1 -0
  8. data/lib/id3tag/tag.rb +2 -2
  9. data/lib/id3tag/version.rb +1 -1
  10. data/spec/features/can_read_non_audio_files_spec.rb +8 -7
  11. data/spec/features/can_read_tag_v1_spec.rb +6 -6
  12. data/spec/lib/id3tag/audio_file_spec.rb +85 -15
  13. data/spec/lib/id3tag/frames/util/genre_name_by_id_finder_spec.rb +2 -2
  14. data/spec/lib/id3tag/frames/v1/comments_frame_spec.rb +7 -7
  15. data/spec/lib/id3tag/frames/v1/genre_frame_spec.rb +3 -3
  16. data/spec/lib/id3tag/frames/v1/text_frame_spec.rb +2 -2
  17. data/spec/lib/id3tag/frames/v1/track_nr_frame_spec.rb +3 -3
  18. data/spec/lib/id3tag/frames/v2/basic_frame_spec.rb +56 -16
  19. data/spec/lib/id3tag/frames/v2/comments_frame_spec.rb +5 -5
  20. data/spec/lib/id3tag/frames/v2/frame_fabricator_spec.rb +8 -8
  21. data/spec/lib/id3tag/frames/v2/frame_flags_spec.rb +539 -108
  22. data/spec/lib/id3tag/frames/v2/genre_frame/genre_parser_24_spec.rb +3 -3
  23. data/spec/lib/id3tag/frames/v2/genre_frame/genre_parser_pre_24_spec.rb +8 -8
  24. data/spec/lib/id3tag/frames/v2/genre_frame_spec.rb +9 -9
  25. data/spec/lib/id3tag/frames/v2/picture_frame_spec.rb +37 -17
  26. data/spec/lib/id3tag/frames/v2/text_frame_spec.rb +7 -7
  27. data/spec/lib/id3tag/frames/v2/unique_file_id_frame_spec.rb +4 -4
  28. data/spec/lib/id3tag/frames/v2/user_text_frame_spec.rb +19 -4
  29. data/spec/lib/id3tag/id3_v1_frame_parser_spec.rb +10 -10
  30. data/spec/lib/id3tag/id3_v2_frame_parser_spec.rb +6 -6
  31. data/spec/lib/id3tag/id3_v2_tag_header_spec.rb +105 -21
  32. data/spec/lib/id3tag/id3tag_spec.rb +1 -1
  33. data/spec/lib/id3tag/io_util_spec.rb +4 -4
  34. data/spec/lib/id3tag/number_util_spec.rb +10 -2
  35. data/spec/lib/id3tag/string_util_spec.rb +10 -10
  36. data/spec/lib/id3tag/synchsafe_integer_spec.rb +6 -6
  37. data/spec/lib/id3tag/tag_spec.rb +192 -91
  38. metadata +28 -29
  39. data/Gemfile.lock +0 -77
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8ccd7d09b5680224f517388b816869e337d1041e
4
- data.tar.gz: 608e4d9b4072420b86b5c53fe85cc30d0c7be16f
3
+ metadata.gz: 29c3cc9a5756c4275ce59da395e80643854f8dec
4
+ data.tar.gz: a5e6942ac0b6fa2d7242682c32506842421f68ac
5
5
  SHA512:
6
- metadata.gz: a82c303f0abc81661f7cf9f8ec2197770ed3fcc9f85254d8680372817fd4569b709bc1942b7055de85e0cbc41f85ad04e15f20e35e52bef4157791d9cfeb503c
7
- data.tar.gz: 77890b09ebe42028bc0f96ede27bc71727563ac56c87d31bc85d6a255a26843311688aac9f8b48ee606826aecd93325cb9a5d99a6995db8198346fda70fde26f
6
+ metadata.gz: 5bcb3bda2e129e52030e22e4bde12b016646205967a7f4ab7be13337d6bca4483f6b3b66217a822a2d9f4f5b22d0b114f58a85b9c853275d23e6a3433218b5dc
7
+ data.tar.gz: d711c5880bfaca342a734ee69c1f9c93e635e09ea62535d145b7dbe000b80ee496a2497e706da9c007b98bedd58afd0288a19d2e4cb23c436b9e4b204c3ebe09
data/.gitignore CHANGED
@@ -1,50 +1,7 @@
1
- # rcov generated
2
1
  coverage
3
- coverage.data
4
-
5
- # rdoc generated
6
- rdoc
7
-
8
- # yard generated
9
- doc
10
- .yardoc
11
-
12
- # bundler
2
+ Gemfile.lock
13
3
  .bundle
14
-
15
- # jeweler generated
16
- pkg
17
4
  tags
5
+ vendor/bundle
6
+ bin
18
7
 
19
- # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
20
- #
21
- # * Create a file at ~/.gitignore
22
- # * Include files you want ignored
23
- # * Run: git config --global core.excludesfile ~/.gitignore
24
- #
25
- # After doing this, these files will be ignored in all your git projects,
26
- # saving you from having to 'pollute' every project you touch with them
27
- #
28
- # Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
29
- #
30
- # For MacOS:
31
- #
32
- #.DS_Store
33
-
34
- # For TextMate
35
- #*.tmproj
36
- #tmtags
37
-
38
- # For emacs:
39
- #*~
40
- #\#*
41
- #.\#*
42
-
43
- # For vim:
44
- #*.swp
45
-
46
- # For redcar:
47
- #.redcar
48
-
49
- # For rubinius:
50
- #*.rbc
data/.travis.yml CHANGED
@@ -1,12 +1,13 @@
1
1
  language: ruby
2
+ before_install:
3
+ - gem install bundler
2
4
  rvm:
3
5
  - ruby-head
4
- - 2.1.2
5
- - 2.0.0
6
- - 1.9.3
7
- - jruby-19mode
8
6
  - jruby-head
9
- - rbx-2
7
+ - 2.3.0
8
+ - 2.2.4
9
+ - 2.1.8
10
+ - jruby-9.0.5.0
10
11
  matrix:
11
12
  allow_failures:
12
13
  - rvm: jruby-head
data/id3tag.gemspec CHANGED
@@ -5,7 +5,7 @@ Gem::Specification.new do |s|
5
5
  s.name = "id3tag"
6
6
  s.version = ID3Tag::VERSION
7
7
  s.authors = ["Krists Ozols"]
8
- s.email = "krists@iesals.lv"
8
+ s.email = "krists.ozols@gmail.com"
9
9
  s.description = "Native Ruby ID3 tag reader that aims for 100% covarage of ID3v2.x and ID3v1.x standards"
10
10
  s.summary = "Native Ruby ID3 tag reader that aims for 100% covarage of ID3v2.x and ID3v1.x standards"
11
11
  s.homepage = "http://github.com/krists/id3tag"
@@ -18,11 +18,11 @@ Gem::Specification.new do |s|
18
18
  s.require_paths = ["lib"]
19
19
  s.required_ruby_version = Gem::Requirement.new(">= 1.9.2")
20
20
 
21
- s.add_development_dependency "bundler", "~> 1.3"
22
- s.add_development_dependency "rake"
23
- s.add_development_dependency "rdoc", "~> 4.1.1"
24
- s.add_development_dependency "rspec", "~> 2.13.0"
25
- s.add_development_dependency "simplecov"
26
- s.add_development_dependency 'coveralls'
27
- s.add_development_dependency 'pry'
21
+ s.add_development_dependency "bundler"
22
+ s.add_development_dependency "rake", "~> 11.1.1"
23
+ s.add_development_dependency "rdoc", "~> 4.2.2"
24
+ s.add_development_dependency "rspec", "~> 3.4.0"
25
+ s.add_development_dependency "simplecov", "~> 0.11.2"
26
+ s.add_development_dependency 'coveralls', "~> 0.8.13"
27
+ s.add_development_dependency 'pry', "~> 0.10.3"
28
28
  end
@@ -24,17 +24,35 @@ module ID3Tag
24
24
  end
25
25
 
26
26
  def v1_tag_body
27
- if @file.size >= ID3V1_TAG_SIZE
28
- @file.seek(-ID3V1_TAG_SIZE + IDV1_TAG_IDENTIFIER.size, IO::SEEK_END)
27
+ if v1_tag_present?
28
+ @file.seek(-v1_tag_size, IO::SEEK_END)
29
+ @file.read
30
+ else
31
+ nil
32
+ end
33
+ end
34
+
35
+ def v1_tag_size
36
+ if v1_tag_present?
37
+ ID3V1_TAG_SIZE - IDV1_TAG_IDENTIFIER.size
29
38
  else
30
- @file.rewind
39
+ 0
31
40
  end
32
- @file.read
33
41
  end
34
42
 
35
43
  def v2_tag_body
36
- @file.seek(v2_tag_frame_and_padding_position)
37
- @file.read(v2_tag_frame_and_padding_size)
44
+ if v2_tag_size > 0
45
+ @file.seek(v2_tag_frame_and_padding_position)
46
+ @file.read(v2_tag_frame_and_padding_size)
47
+ end
48
+ end
49
+
50
+ def v2_tag_size
51
+ if v2_tag_present?
52
+ v2_tag_header.tag_size
53
+ else
54
+ 0
55
+ end
38
56
  end
39
57
 
40
58
  def v2_tag_version
@@ -19,19 +19,19 @@ module ID3Tag
19
19
  end
20
20
 
21
21
  def unsynchronisation?
22
- flags_byte[7] == 1
22
+ 0b1000_0000 & flags_byte > 0
23
23
  end
24
24
 
25
25
  def extended_header?
26
- flags_byte[6] == 1
26
+ 0b100_0000 & flags_byte > 0
27
27
  end
28
28
 
29
29
  def experimental?
30
- flags_byte[5] == 1
30
+ 0b10_0000 & flags_byte > 0
31
31
  end
32
32
 
33
33
  def footer_present?
34
- flags_byte[4] == 1
34
+ 0b1_0000 & flags_byte > 0
35
35
  end
36
36
 
37
37
  def tag_size
@@ -3,6 +3,7 @@ module ID3Tag
3
3
  FORMAT_FOR_8_BIT_SIGNED_INTEGER = 'c'
4
4
  FORMAT_FOR_32BIT_INTEGER = 'N'
5
5
  def self.convert_string_to_32bit_integer(string)
6
+ raise(ArgumentError, "Input must be a string. #{string.inspect} given.") unless string.is_a?(::String)
6
7
  integers = string.unpack(FORMAT_FOR_32BIT_INTEGER)
7
8
  integers.first || raise(ArgumentError, "String: '#{string}' could not be decoded as 32-bit integer")
8
9
  end
data/lib/id3tag/tag.rb CHANGED
@@ -112,11 +112,11 @@ module ID3Tag
112
112
  end
113
113
 
114
114
  def should_and_could_read_v1_frames?
115
- scope.include?(:v1) && audio_file.v1_tag_present?
115
+ scope.include?(:v1) && audio_file.v1_tag_present? && audio_file.v1_tag_size > 0
116
116
  end
117
117
 
118
118
  def should_and_could_read_v2_frames?
119
- scope.include?(:v2) && audio_file.v2_tag_present?
119
+ scope.include?(:v2) && audio_file.v2_tag_present? && audio_file.v2_tag_size > 0
120
120
  end
121
121
  end
122
122
  end
@@ -1,3 +1,3 @@
1
1
  module ID3Tag
2
- VERSION = "0.8.0"
2
+ VERSION = "0.9.0"
3
3
  end
@@ -5,12 +5,13 @@ describe 'can read any file and does not raise errors if no tag found' do
5
5
  subject { ID3Tag.read(Tempfile.new('fake_mp3')) }
6
6
 
7
7
  it 'should return blanks' do
8
- subject.title.should == nil
9
- subject.artist.should == nil
10
- subject.album.should == nil
11
- subject.genre.should == nil
12
- subject.year.should == nil
13
- subject.track_nr.should == nil
14
- subject.frames.should == []
8
+ expect(subject.title).to eq(nil)
9
+ expect(subject.artist).to eq(nil)
10
+ expect(subject.album).to eq(nil)
11
+ expect(subject.genre).to eq(nil)
12
+ expect(subject.year).to eq(nil)
13
+ expect(subject.track_nr).to eq(nil)
14
+ expect(subject.frames).to eq([])
15
+ expect(subject.frame_ids).to eq([])
15
16
  end
16
17
  end
@@ -5,11 +5,11 @@ describe 'can read v1 info from file' do
5
5
  subject { ID3Tag.read(mp3_with_v1_1_tag) }
6
6
 
7
7
  it 'reading file with only v1 tag' do
8
- subject.title.should == "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaA"
9
- subject.artist.should == "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbB"
10
- subject.album.should == "cccccccccccccccccccccccccccccC"
11
- subject.genre.should == "Blues"
12
- subject.year.should == "2003"
13
- subject.track_nr.should == "1"
8
+ expect(subject.title).to eq("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaA")
9
+ expect(subject.artist).to eq("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbB")
10
+ expect(subject.album).to eq("cccccccccccccccccccccccccccccC")
11
+ expect(subject.genre).to eq("Blues")
12
+ expect(subject.year).to eq("2003")
13
+ expect(subject.track_nr).to eq("1")
14
14
  end
15
15
  end
@@ -3,31 +3,89 @@ describe ID3Tag::AudioFile do
3
3
  let(:mp3_with_v1_tag) { mp3_fixture('id3v1_without_track_nr.mp3') }
4
4
  let(:mp3_with_v2_tag) { mp3_fixture('id3v2.mp3') }
5
5
  let(:mp3_with_v1_and_v2_tags) { mp3_fixture('id3v1_and_v2.mp3') }
6
+ let(:broken_mp3) do
7
+ file = Tempfile.new("broken_mp3")
8
+ file.write("just something..but not enough")
9
+ file
10
+ end
6
11
 
7
12
  describe "Tag presence checking methods" do
8
13
  context "reading file only with ID3v1 tag" do
9
14
  subject { described_class.new(mp3_with_v1_tag) }
10
- its(:v1_tag_present?) { should be_true }
11
- its(:v2_tag_present?) { should be_false }
15
+
16
+ describe '#v1_tag_present?' do
17
+ subject { super().v1_tag_present? }
18
+ it { is_expected.to eq(true) }
19
+ end
20
+
21
+ describe '#v1_tag_size' do
22
+ subject { super().v1_tag_size }
23
+ it { is_expected.to eq(125) }
24
+ end
25
+
26
+
27
+ describe '#v2_tag_present?' do
28
+ subject { super().v2_tag_present? }
29
+ it { is_expected.to eq(false) }
30
+ end
31
+
32
+ describe '#v2_tag_size' do
33
+ subject { super().v2_tag_size }
34
+ it { is_expected.to eq(0) }
35
+ end
12
36
  end
13
37
 
14
38
  context "reading file only with ID3v2 tag" do
15
39
  subject { described_class.new(mp3_with_v2_tag) }
16
- its(:v1_tag_present?) { should be_false }
17
- its(:v2_tag_present?) { should be_true }
40
+
41
+ describe '#v1_tag_present?' do
42
+ subject { super().v1_tag_present? }
43
+ it { is_expected.to eq(false) }
44
+ end
45
+
46
+ describe '#v1_tag_size' do
47
+ subject { super().v1_tag_size }
48
+ it { is_expected.to eq(0) }
49
+ end
50
+
51
+ describe '#v2_tag_present?' do
52
+ subject { super().v2_tag_present? }
53
+ it { is_expected.to eq(true) }
54
+ end
55
+
56
+ describe '#v2_tag_size' do
57
+ subject { super().v2_tag_size }
58
+ it { is_expected.to eq(246) }
59
+ end
18
60
  end
19
61
 
20
62
  context "reading file with ID3v1 and ID3v2 tags" do
21
63
  subject { described_class.new(mp3_with_v1_and_v2_tags) }
22
- its(:v1_tag_present?) { should be_true }
23
- its(:v2_tag_present?) { should be_true }
64
+
65
+ describe '#v1_tag_present?' do
66
+ subject { super().v1_tag_present? }
67
+ it { is_expected.to eq(true) }
68
+ end
69
+
70
+ describe '#v2_tag_present?' do
71
+ subject { super().v2_tag_present? }
72
+ it { is_expected.to eq(true) }
73
+ end
24
74
  end
25
75
  end
26
76
 
27
77
  describe "#v1_tag_body" do
28
- subject { described_class.new(mp3_with_v1_tag) }
29
- it "should return last 125 bytes of audio file" do
30
- subject.v1_tag_body.should == File.read(mp3_with_v1_tag, 125, 579)
78
+ context "when reading file with alteast 125 bytes" do
79
+ subject { described_class.new(mp3_with_v1_tag) }
80
+ it "should return last 125 bytes of audio file" do
81
+ expect(subject.v1_tag_body).to eq(File.read(mp3_with_v1_tag, 125, 579))
82
+ end
83
+ end
84
+ context "when reading file with size less ID3v1 tag" do
85
+ subject { described_class.new(broken_mp3) }
86
+ it "should return as much bytes as possible" do
87
+ expect(subject.v1_tag_body).to eq(nil)
88
+ end
31
89
  end
32
90
  end
33
91
 
@@ -35,18 +93,18 @@ describe ID3Tag::AudioFile do
35
93
  context "when extended header is not present" do
36
94
  subject { described_class.new(StringIO.new("ID3\u0003\u0000\u0000\u0000\u0000\u0000\u0003ABC")) }
37
95
  it "should return frame and padding bytes" do
38
- subject.v2_tag_body.should == "ABC"
96
+ expect(subject.v2_tag_body).to eq("ABC")
39
97
  end
40
98
  end
41
99
  context "when extended header is present" do
42
100
  subject { described_class.new(StringIO.new("ID3\u0003\u0000\u0040\u0000\u0000\u0000\u0011" + "\u0000\u0000\u0000\u000A" + ("\u0000" * 10) + "ABC")) }
43
101
  it "should return frame and padding bytes" do
44
- subject.v2_tag_body.should == "ABC"
102
+ expect(subject.v2_tag_body).to eq("ABC")
45
103
  end
46
104
  context "when tag verison is v.2.4 and extended header size is calculated differently" do
47
105
  subject { described_class.new(StringIO.new("ID3\u0004\u0000\u0040\u0000\u0000\u0000\u0011" + "\u0000\u0000\u0000\u000A" + ("\u0000" * 6) + "ABC")) }
48
106
  it "should return frame and padding bytes" do
49
- subject.v2_tag_body.should == "ABC"
107
+ expect(subject.v2_tag_body).to eq("ABC")
50
108
  end
51
109
  end
52
110
  end
@@ -54,8 +112,20 @@ describe ID3Tag::AudioFile do
54
112
 
55
113
  context "when reading file with v2.3.0 tag" do
56
114
  subject { described_class.new(StringIO.new("ID3\u0003\u0000")) }
57
- its(:v2_tag_version) { should eq '3.0' }
58
- its(:v2_tag_major_version_number) { should eq 3 }
59
- its(:v2_tag_minor_version_number) { should eq 0 }
115
+
116
+ describe '#v2_tag_version' do
117
+ subject { super().v2_tag_version }
118
+ it { is_expected.to eq '3.0' }
119
+ end
120
+
121
+ describe '#v2_tag_major_version_number' do
122
+ subject { super().v2_tag_major_version_number }
123
+ it { is_expected.to eq 3 }
124
+ end
125
+
126
+ describe '#v2_tag_minor_version_number' do
127
+ subject { super().v2_tag_minor_version_number }
128
+ it { is_expected.to eq 0 }
129
+ end
60
130
  end
61
131
  end
@@ -7,12 +7,12 @@ describe ID3Tag::Frames::Util::GenreNames do
7
7
 
8
8
  context "when calling with id 0 what represents Blues" do
9
9
  let(:id) { 0 }
10
- it { should eq('Blues') }
10
+ it { is_expected.to eq('Blues') }
11
11
  end
12
12
 
13
13
  context "when calling with id 17 what represents Rock" do
14
14
  let(:id) { 17 }
15
- it { should eq('Rock') }
15
+ it { is_expected.to eq('Rock') }
16
16
  end
17
17
  end
18
18
  end
@@ -2,38 +2,38 @@ require 'spec_helper'
2
2
  describe ID3Tag::Frames::V1::CommentsFrame do
3
3
  describe '#id' do
4
4
  subject { described_class.new('comments', nil).id }
5
- it { should == 'comments' }
5
+ it { is_expected.to eq('comments') }
6
6
  end
7
7
 
8
8
  describe '#content' do
9
9
  context 'when comment is present' do
10
10
  subject { described_class.new('comments', 'some comment about the song').content }
11
- it { should == 'some comment about the song' }
11
+ it { is_expected.to eq('some comment about the song') }
12
12
  end
13
13
 
14
14
  context 'when comment is not present' do
15
15
  subject { described_class.new('comments', '').content }
16
- it { should == '' }
16
+ it { is_expected.to eq('') }
17
17
  end
18
18
  end
19
19
 
20
20
  describe "#text" do
21
21
  subject { described_class.new('comments', 'some comment about the song') }
22
22
  it "should be the same as #content" do
23
- subject.stub(:content) { "ZXC" }
24
- subject.text.should == subject.content
23
+ allow(subject).to receive(:content) { "ZXC" }
24
+ expect(subject.text).to eq(subject.content)
25
25
  end
26
26
  end
27
27
 
28
28
  describe '#language' do
29
29
  it 'should be unknown' do
30
- described_class.new('comments', '').language.should eq('unknown')
30
+ expect(described_class.new('comments', '').language).to eq('unknown')
31
31
  end
32
32
  end
33
33
 
34
34
  describe '#desciption' do
35
35
  it 'should be unknown' do
36
- described_class.new('comments', '').desciption.should eq('unknown')
36
+ expect(described_class.new('comments', '').desciption).to eq('unknown')
37
37
  end
38
38
  end
39
39
  end