id3tag 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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