taglib-ruby 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/taglib.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'taglib/version'
1
2
  require 'taglib/base'
2
3
  require 'taglib/mpeg'
3
4
  require 'taglib/id3v2'
data/lib/taglib/id3v2.rb CHANGED
@@ -2,40 +2,18 @@ require 'taglib_id3v2'
2
2
 
3
3
  module TagLib
4
4
  module ID3v2
5
- class FrameList
6
- include Enumerable
7
-
8
- def each
9
- it = self.begin
10
- it_end = self.end
11
- while it != it_end
12
- frame = it.value
13
- casted_frame = frame.cast
14
- yield casted_frame
15
- it = it.next
16
- end
17
- end
18
- end
19
5
  class Frame
20
6
  def to_s
21
7
  to_string
22
8
  end
23
- def cast
24
- case frame_id
25
- when "APIC" then to_attached_picture_frame
26
- when "COMM" then to_comments_frame
27
- when "GEOB" then to_general_encapsulated_object_frame
28
- when "POPM" then to_popularimeter_frame
29
- when "PRIV" then to_private_frame
30
- when "RVAD" then to_relative_volume_frame
31
- when "TXXX" then to_user_text_identification_frame
32
- when /T.../ then to_text_identification_frame
33
- when "UFID" then to_unique_file_identifier_frame
34
- when "USLT" then to_unsynchronized_lyrics_frame
35
- when "WXXX" then to_user_url_link_frame
36
- when /W.../ then to_url_link_frame
37
- else self
38
- end
9
+
10
+ def inspect
11
+ # Overwrite inspect because Object#inspect calls to_s. In case
12
+ # of an unlinked frame, calling to_s would lead to calling into
13
+ # SWIG through to_string, which in turn would raise an exception
14
+ # with a message including an inspect of this object, which
15
+ # would call to_s -> stack overflow.
16
+ "#<%s:0x%x>" % [self.class.to_s, object_id << 1]
39
17
  end
40
18
  end
41
19
  end
@@ -1,8 +1,8 @@
1
1
  module TagLib
2
2
  module Version
3
3
  MAJOR = 0
4
- MINOR = 1
5
- PATCH = 1
4
+ MINOR = 2
5
+ PATCH = 0
6
6
  BUILD = nil
7
7
 
8
8
  STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.')
data/taglib-ruby.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "taglib-ruby"
8
- s.version = "0.1.1"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Robin Stocker"]
12
- s.date = "2011-09-17"
12
+ s.date = "2011-10-22"
13
13
  s.description = "Ruby interface for the taglib C++ library.\n\nIn contrast to other libraries, this one wraps the C++ API using SWIG,\nnot only the minimal C API. This means that all tags can be accessed.\n"
14
14
  s.email = "robin@nibor.org"
15
15
  s.extensions = ["ext/taglib_base/extconf.rb", "ext/taglib_mpeg/extconf.rb", "ext/taglib_id3v2/extconf.rb"]
@@ -18,11 +18,18 @@ Gem::Specification.new do |s|
18
18
  "README.md"
19
19
  ]
20
20
  s.files = [
21
+ ".yardopts",
22
+ "CHANGES.md",
21
23
  "Gemfile",
22
24
  "Gemfile.lock",
25
+ "Guardfile",
23
26
  "LICENSE.txt",
24
27
  "README.md",
25
28
  "Rakefile",
29
+ "docs/default/fulldoc/html/css/common.css",
30
+ "docs/taglib/base.rb",
31
+ "docs/taglib/id3v2.rb",
32
+ "docs/taglib/mpeg.rb",
26
33
  "ext/Rakefile",
27
34
  "ext/extconf_common.rb",
28
35
  "ext/taglib_base/extconf.rb",
@@ -30,6 +37,7 @@ Gem::Specification.new do |s|
30
37
  "ext/taglib_base/taglib_base.i",
31
38
  "ext/taglib_base/taglib_base_wrap.cxx",
32
39
  "ext/taglib_id3v2/extconf.rb",
40
+ "ext/taglib_id3v2/relativevolumeframe.i",
33
41
  "ext/taglib_id3v2/taglib_id3v2.i",
34
42
  "ext/taglib_id3v2/taglib_id3v2_wrap.cxx",
35
43
  "ext/taglib_mpeg/extconf.rb",
@@ -42,15 +50,22 @@ Gem::Specification.new do |s|
42
50
  "lib/taglib/mpeg.rb",
43
51
  "lib/taglib/version.rb",
44
52
  "taglib-ruby.gemspec",
53
+ "tasks/docs_coverage.rake",
54
+ "test/data/add-relative-volume.cpp",
55
+ "test/data/crash.mp3",
45
56
  "test/data/globe_east_540.jpg",
57
+ "test/data/relative-volume.mp3",
46
58
  "test/data/sample.mp3",
47
59
  "test/data/unicode.mp3",
48
60
  "test/helper.rb",
61
+ "test/test_fileref_properties.rb",
49
62
  "test/test_id3v2_frames.rb",
50
63
  "test/test_id3v2_memory.rb",
64
+ "test/test_id3v2_relative_volume.rb",
51
65
  "test/test_id3v2_tag.rb",
52
66
  "test/test_id3v2_unicode.rb",
53
67
  "test/test_id3v2_write.rb",
68
+ "test/test_mpeg_file.rb",
54
69
  "test/test_tag.rb"
55
70
  ]
56
71
  s.homepage = "http://github.com/robinst/taglib-ruby"
@@ -69,14 +84,18 @@ Gem::Specification.new do |s|
69
84
  s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
70
85
  s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
71
86
  s.add_development_dependency(%q<rcov>, [">= 0"])
72
- s.add_development_dependency(%q<rdoc>, ["~> 3.9"])
87
+ s.add_development_dependency(%q<yard>, ["~> 0.7"])
88
+ s.add_development_dependency(%q<redcarpet>, [">= 0"])
89
+ s.add_development_dependency(%q<guard-test>, ["~> 0.4.0"])
73
90
  else
74
91
  s.add_dependency(%q<rake-compiler>, ["~> 0.7"])
75
92
  s.add_dependency(%q<shoulda>, ["~> 2.11"])
76
93
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
77
94
  s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
78
95
  s.add_dependency(%q<rcov>, [">= 0"])
79
- s.add_dependency(%q<rdoc>, ["~> 3.9"])
96
+ s.add_dependency(%q<yard>, ["~> 0.7"])
97
+ s.add_dependency(%q<redcarpet>, [">= 0"])
98
+ s.add_dependency(%q<guard-test>, ["~> 0.4.0"])
80
99
  end
81
100
  else
82
101
  s.add_dependency(%q<rake-compiler>, ["~> 0.7"])
@@ -84,7 +103,9 @@ Gem::Specification.new do |s|
84
103
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
85
104
  s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
86
105
  s.add_dependency(%q<rcov>, [">= 0"])
87
- s.add_dependency(%q<rdoc>, ["~> 3.9"])
106
+ s.add_dependency(%q<yard>, ["~> 0.7"])
107
+ s.add_dependency(%q<redcarpet>, [">= 0"])
108
+ s.add_dependency(%q<guard-test>, ["~> 0.4.0"])
88
109
  end
89
110
  end
90
111
 
@@ -0,0 +1,26 @@
1
+ desc "Show the coverage of the actual API in ext/ by the API docs in docs/"
2
+ task :docs_coverage do |t|
3
+ def sort(objects)
4
+ objects.sort_by { |obj| obj.path }
5
+ end
6
+
7
+ YARD.parse("ext/**/*_wrap.cxx")
8
+ ext_codeobjects = sort(YARD::Registry.all)
9
+ YARD::Registry.clear
10
+ YARD.parse("docs/**/*.rb")
11
+ docs_codeobjects = sort(YARD::Registry.all(:module, :class, :method))
12
+
13
+ only_in_ext = (ext_codeobjects - docs_codeobjects)
14
+ only_in_docs = (docs_codeobjects - ext_codeobjects)
15
+
16
+ unless only_in_ext.empty?
17
+ puts
18
+ puts "=== Only in ext (to document): "
19
+ puts only_in_ext
20
+ end
21
+ unless only_in_docs.empty?
22
+ puts
23
+ puts "=== Only in docs (typo?): "
24
+ puts only_in_docs
25
+ end
26
+ end
@@ -0,0 +1,40 @@
1
+ #include <iostream>
2
+ #include <stdlib.h>
3
+
4
+ #include <taglib/taglib.h>
5
+ #include <taglib/mpegfile.h>
6
+ #include <taglib/id3v2tag.h>
7
+ #include <taglib/relativevolumeframe.h>
8
+
9
+ using namespace TagLib;
10
+
11
+ int main(int argc, char **argv) {
12
+ if (argc != 2) {
13
+ std::cout << "usage: " << argv[0] << " file.mp3" << std::endl;
14
+ exit(1);
15
+ }
16
+ char *filename = argv[1];
17
+
18
+ MPEG::File file(filename);
19
+ ID3v2::Tag *tag = file.ID3v2Tag(true);
20
+
21
+ ID3v2::RelativeVolumeFrame *rv = new ID3v2::RelativeVolumeFrame();
22
+
23
+ rv->setVolumeAdjustmentIndex(512);
24
+ rv->setVolumeAdjustmentIndex(1024, ID3v2::RelativeVolumeFrame::Subwoofer);
25
+
26
+ ID3v2::RelativeVolumeFrame::PeakVolume pv1;
27
+ pv1.bitsRepresentingPeak = 8;
28
+ pv1.peakVolume = "A"; // 0x41, 0b01000001
29
+ rv->setPeakVolume(pv1);
30
+
31
+ ID3v2::RelativeVolumeFrame::PeakVolume pv2;
32
+ pv2.bitsRepresentingPeak = 4;
33
+ pv2.peakVolume = "?"; // 0x3F, 0b00111111
34
+ rv->setPeakVolume(pv2, ID3v2::RelativeVolumeFrame::Subwoofer);
35
+
36
+ tag->addFrame(rv);
37
+ file.save();
38
+ }
39
+
40
+ // vim: set filetype=cpp sw=2 ts=2 expandtab:
Binary file
Binary file
@@ -0,0 +1,21 @@
1
+ require 'helper'
2
+
3
+ class TestFileRefProperties < Test::Unit::TestCase
4
+ context "The crash.mp3 file audio properties" do
5
+ setup do
6
+ @fileref = TagLib::FileRef.new("test/data/crash.mp3", true, TagLib::AudioProperties::Average)
7
+ @properties = @fileref.audio_properties
8
+ end
9
+
10
+ should "exist" do
11
+ assert_not_nil @properties
12
+ end
13
+
14
+ should "contain basic information" do
15
+ assert_equal 2, @properties.length
16
+ assert_equal 157, @properties.bitrate
17
+ assert_equal 44100, @properties.sample_rate
18
+ assert_equal 2, @properties.channels
19
+ end
20
+ end
21
+ end
@@ -20,8 +20,7 @@ class TestID3v2Frames < Test::Unit::TestCase
20
20
  should "be complete" do
21
21
  assert_not_nil @frames
22
22
  assert_equal 11, @frames.size
23
- iterator = @frames.begin
24
- frame = iterator.value
23
+ frame = @frames.first
25
24
  assert_equal "Dummy Title", frame.to_string
26
25
  end
27
26
 
@@ -35,9 +34,32 @@ class TestID3v2Frames < Test::Unit::TestCase
35
34
  apic = @tag.frame_list('APIC').first
36
35
  comm = @tag.frame_list('COMM').first
37
36
  tit2 = @tag.frame_list('TIT2').first
37
+ txxx = @tag.frame_list('TXXX').first
38
38
  assert_equal TagLib::ID3v2::AttachedPictureFrame, apic.class
39
39
  assert_equal TagLib::ID3v2::CommentsFrame, comm.class
40
40
  assert_equal TagLib::ID3v2::TextIdentificationFrame, tit2.class
41
+ assert_equal TagLib::ID3v2::UserTextIdentificationFrame, txxx.class
42
+ end
43
+
44
+ should "be removable" do
45
+ assert_equal 11, @tag.frame_list.size
46
+ tit2 = @tag.frame_list('TIT2').first
47
+ @tag.remove_frame(tit2)
48
+ assert_equal 10, @tag.frame_list.size
49
+ begin
50
+ tit2.to_string
51
+ flunk("Should have raised ObjectPreviouslyDeleted.")
52
+ rescue => e
53
+ assert_equal "ObjectPreviouslyDeleted", e.class.to_s
54
+ end
55
+ end
56
+
57
+ should "be removable by ID" do
58
+ frames = @tag.frame_list
59
+ @tag.remove_frames('COMM')
60
+ tit2 = frames.find{ |f| f.frame_id == 'TIT2' }
61
+ # Other frames should still be accessible
62
+ assert_equal "Dummy Title", tit2.to_s
41
63
  end
42
64
 
43
65
  context "APIC frame" do
@@ -77,12 +99,7 @@ class TestID3v2Frames < Test::Unit::TestCase
77
99
 
78
100
  should "have to_s" do
79
101
  expected = "[MusicBrainz Album Id] MusicBrainz Album Id 992dc19a-5631-40f5-b252-fbfedbc328a9"
80
- assert_equal expected, @txxx_frame.to_s
81
- end
82
-
83
- should "be convertable to its concrete type" do
84
- txxx = @txxx_frame.to_user_text_identification_frame
85
- assert_equal TagLib::ID3v2::UserTextIdentificationFrame, txxx.class
102
+ assert_equal expected, @txxx_frame.to_string
86
103
  end
87
104
 
88
105
  should "have field_list" do
@@ -0,0 +1,57 @@
1
+ require 'helper'
2
+
3
+ class TestID3v2RelativeVolumeFrame < Test::Unit::TestCase
4
+ context "The relative-volume.mp3 RVA2 frame" do
5
+ setup do
6
+ @file = TagLib::MPEG::File.new("test/data/relative-volume.mp3")
7
+ @tag = @file.id3v2_tag
8
+ @rv = @tag.frame_list('RVA2').first
9
+ end
10
+
11
+ should "exist" do
12
+ assert_not_nil @rv
13
+ end
14
+
15
+ should "have channels" do
16
+ expected = [TagLib::ID3v2::RelativeVolumeFrame::MasterVolume, TagLib::ID3v2::RelativeVolumeFrame::Subwoofer]
17
+ assert_equal expected, @rv.channels
18
+ end
19
+
20
+ should "have volume adjustments" do
21
+ assert_equal 512, @rv.volume_adjustment_index
22
+ assert_equal 1.0, @rv.volume_adjustment
23
+ assert_equal 1024, @rv.volume_adjustment_index(TagLib::ID3v2::RelativeVolumeFrame::Subwoofer)
24
+ assert_equal 2.0, @rv.volume_adjustment(TagLib::ID3v2::RelativeVolumeFrame::Subwoofer)
25
+ end
26
+
27
+ should "have peak volumes" do
28
+ master_pv = @rv.peak_volume
29
+ assert_equal 8, master_pv.bits_representing_peak
30
+ assert_equal 0b01000001.chr, master_pv.peak_volume
31
+
32
+ subwoofer_pv = @rv.peak_volume(TagLib::ID3v2::RelativeVolumeFrame::Subwoofer)
33
+ assert_equal 4, subwoofer_pv.bits_representing_peak
34
+ assert_equal 0b00111111.chr, subwoofer_pv.peak_volume
35
+ end
36
+
37
+ should "accept new volume adjustments" do
38
+ @rv.set_volume_adjustment_index(2048, TagLib::ID3v2::RelativeVolumeFrame::FrontCentre)
39
+ assert_equal 2048, @rv.volume_adjustment_index(TagLib::ID3v2::RelativeVolumeFrame::FrontCentre)
40
+ @rv.set_volume_adjustment(4.0, TagLib::ID3v2::RelativeVolumeFrame::FrontLeft)
41
+ assert_equal 4.0, @rv.volume_adjustment(TagLib::ID3v2::RelativeVolumeFrame::FrontLeft)
42
+ end
43
+
44
+ should "accept new peak volumes" do
45
+ pv = TagLib::ID3v2::PeakVolume.new
46
+ assert_equal 0, pv.bits_representing_peak
47
+ assert_equal "", pv.peak_volume
48
+ pv.bits_representing_peak = 6
49
+ pv.peak_volume = 0b110111.chr
50
+ @rv.set_peak_volume(pv, TagLib::ID3v2::RelativeVolumeFrame::BackLeft)
51
+
52
+ pv2 = @rv.peak_volume(TagLib::ID3v2::RelativeVolumeFrame::BackLeft)
53
+ assert_equal 6, pv2.bits_representing_peak
54
+ assert_equal 0b110111.chr, pv2.peak_volume
55
+ end
56
+ end
57
+ end
@@ -28,4 +28,27 @@ class TestID3v2Tag < Test::Unit::TestCase
28
28
  end
29
29
  end
30
30
  end
31
+
32
+ context "A new ID3v2::Tag" do
33
+ setup do
34
+ @tag = TagLib::ID3v2::Tag.new
35
+ end
36
+
37
+ should "be empty" do
38
+ assert @tag.empty?
39
+ end
40
+
41
+ should "have nil for string attributes" do
42
+ assert_nil @tag.title
43
+ assert_nil @tag.artist
44
+ assert_nil @tag.album
45
+ assert_nil @tag.comment
46
+ assert_nil @tag.genre
47
+ end
48
+
49
+ should "have 0 for numeric attributes" do
50
+ assert_equal 0, @tag.track
51
+ assert_equal 0, @tag.year
52
+ end
53
+ end
31
54
  end
@@ -0,0 +1,49 @@
1
+ require 'helper'
2
+
3
+ class TestMPEGFile < Test::Unit::TestCase
4
+ context "The crash.mp3 file" do
5
+ setup do
6
+ read_properties = true
7
+ @file = TagLib::MPEG::File.new("test/data/crash.mp3", read_properties)
8
+ end
9
+
10
+ context "audio properties" do
11
+ setup do
12
+ @properties = @file.audio_properties
13
+ end
14
+
15
+ should "be MPEG audio properties" do
16
+ assert_equal TagLib::MPEG::Properties, @properties.class
17
+ end
18
+
19
+ should "contain information" do
20
+ assert_equal 2, @properties.length
21
+ assert_equal 157, @properties.bitrate
22
+ assert_equal 44100, @properties.sample_rate
23
+ assert_equal 2, @properties.channels
24
+ assert_equal TagLib::MPEG::Header::Version1, @properties.version
25
+ assert_equal 3, @properties.layer
26
+ assert_equal false, @properties.protection_enabled
27
+ assert_equal TagLib::MPEG::Header::JointStereo, @properties.channel_mode
28
+ assert_equal false, @properties.copyrighted?
29
+ assert_equal true, @properties.original?
30
+ end
31
+
32
+ context "Xing header" do
33
+ setup do
34
+ @xing_header = @properties.xing_header
35
+ end
36
+
37
+ should "exist" do
38
+ assert_not_nil @xing_header
39
+ end
40
+
41
+ should "contain information" do
42
+ assert_true @xing_header.valid?
43
+ assert_equal 88, @xing_header.total_frames
44
+ assert_equal 45140, @xing_header.total_size
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end