id3tag 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- NzNiYTE0YzFlYTA3ZGVhZDVhMDA4ZWUwNTU4ODcxNTc0ODQzMDg4MQ==
5
- data.tar.gz: !binary |-
6
- ODNiYzM1NTUzNDg4YmJiNGExY2M4YjdkZjg4MjZlODYzMDc1YzNlOA==
7
- !binary "U0hBNTEy":
8
- metadata.gz: !binary |-
9
- NTc3ZDYzY2FiYWEwNTgzOGU4MjM1NDYxYTU1NDgyNzZlYWVhNGRjOTAzZDk1
10
- YmVhMTViOThlYmMxZDRkNzVmMDRkMGViZGU2MWY5ZjViY2IxMTMyOTIwYjUy
11
- NmRhZWNkNDliMjA2MDliMGFmNDM3MzI5NWVmZTM0OTNjY2QzMmM=
12
- data.tar.gz: !binary |-
13
- MGE3NWQwMGM4MmQ3M2E3ZTkxNWMxYzkzODk2MTAxOThjYTc4ODllMGI1Yjgy
14
- MGU1ZTdhZTMyYjdlYmFmMzFlMDZiZjIyN2IzMzk0NjYxZTJiNzk3YzdjMzg0
15
- OTNmN2EwMWY5NGM3MzZkMmEwZDkwZmI0MmZkYTY2NzNiNjkzNTk=
2
+ SHA1:
3
+ metadata.gz: d7e015abc718273110bec0cb6fcdb8036de50f37
4
+ data.tar.gz: 0b3b5d6b9acdd5cf5393fc9a97ef594f393e0101
5
+ SHA512:
6
+ metadata.gz: 1db6cc3bd2407e2bfc6a172e508adc8b11907bd00903b9006aea4b94d0d1c8c620351dc6f22de95405ea6fb16e0784b42456bbde45121fdc56b1e0b44bb0f6e3
7
+ data.tar.gz: 3357247645ce3d9c07be8b0633c95a782361471297bc9bfaefc2d1566db2f4f584adba69c0678dab721e2597986fb9aa11e45149e3c4a13fb2df8cd678da6fa5
data/Gemfile.lock CHANGED
@@ -1,32 +1,63 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- colorize (0.5.8)
4
+ addressable (2.3.5)
5
+ builder (3.2.2)
5
6
  columnize (0.3.6)
6
- coveralls (0.6.7)
7
- colorize
7
+ coveralls (0.7.0)
8
8
  multi_json (~> 1.3)
9
9
  rest-client
10
10
  simplecov (>= 0.7)
11
+ term-ansicolor
11
12
  thor
12
- debugger (1.5.0)
13
+ debugger (1.6.2)
13
14
  columnize (>= 0.3.1)
14
15
  debugger-linecache (~> 1.2.0)
15
- debugger-ruby_core_source (~> 1.2.0)
16
+ debugger-ruby_core_source (~> 1.2.3)
16
17
  debugger-linecache (1.2.0)
17
- debugger-ruby_core_source (1.2.0)
18
- diff-lcs (1.2.2)
19
- git (1.2.5)
20
- jeweler (1.8.4)
18
+ debugger-ruby_core_source (1.2.3)
19
+ diff-lcs (1.2.4)
20
+ faraday (0.8.8)
21
+ multipart-post (~> 1.2.0)
22
+ git (1.2.6)
23
+ github_api (0.10.1)
24
+ addressable
25
+ faraday (~> 0.8.1)
26
+ hashie (>= 1.2)
27
+ multi_json (~> 1.4)
28
+ nokogiri (~> 1.5.2)
29
+ oauth2
30
+ hashie (2.0.5)
31
+ highline (1.6.19)
32
+ httpauth (0.2.0)
33
+ jeweler (1.8.8)
34
+ builder
21
35
  bundler (~> 1.0)
22
36
  git (>= 1.2.5)
37
+ github_api (= 0.10.1)
38
+ highline (>= 1.6.15)
39
+ nokogiri (= 1.5.10)
23
40
  rake
24
41
  rdoc
25
- json (1.7.7)
26
- json (1.7.7-java)
27
- mime-types (1.23)
28
- multi_json (1.6.1)
29
- rake (10.0.3)
42
+ json (1.8.0)
43
+ json (1.8.0-java)
44
+ jwt (0.1.8)
45
+ multi_json (>= 1.5)
46
+ mime-types (1.25)
47
+ multi_json (1.8.2)
48
+ multi_xml (0.5.5)
49
+ multipart-post (1.2.0)
50
+ nokogiri (1.5.10)
51
+ nokogiri (1.5.10-java)
52
+ oauth2 (0.9.2)
53
+ faraday (~> 0.8)
54
+ httpauth (~> 0.2)
55
+ jwt (~> 0.1.4)
56
+ multi_json (~> 1.0)
57
+ multi_xml (~> 0.5)
58
+ rack (~> 1.2)
59
+ rack (1.5.2)
60
+ rake (10.1.0)
30
61
  rdoc (3.12.2)
31
62
  json (~> 1.4)
32
63
  rest-client (1.6.7)
@@ -38,12 +69,15 @@ GEM
38
69
  rspec-core (2.13.1)
39
70
  rspec-expectations (2.13.0)
40
71
  diff-lcs (>= 1.1.3, < 2.0)
41
- rspec-mocks (2.13.0)
72
+ rspec-mocks (2.13.1)
42
73
  simplecov (0.7.1)
43
74
  multi_json (~> 1.0)
44
75
  simplecov-html (~> 0.7.1)
45
76
  simplecov-html (0.7.1)
77
+ term-ansicolor (1.2.2)
78
+ tins (~> 0.8)
46
79
  thor (0.18.1)
80
+ tins (0.12.0)
47
81
 
48
82
  PLATFORMS
49
83
  java
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.2.0
data/id3tag.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "id3tag"
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 = ["Krists Ozols"]
12
- s.date = "2013-05-13"
12
+ s.date = "2013-10-19"
13
13
  s.description = "Native Ruby ID3 tag reader that aims for 100% covarage of ID3v2.x and ID3v1.x standards"
14
14
  s.email = "krists@iesals.lv"
15
15
  s.extra_rdoc_files = [
@@ -38,6 +38,7 @@ Gem::Specification.new do |s|
38
38
  "lib/id3tag/frames/v2/basic_frame.rb",
39
39
  "lib/id3tag/frames/v2/comments_frame.rb",
40
40
  "lib/id3tag/frames/v2/frame_fabricator.rb",
41
+ "lib/id3tag/frames/v2/frame_flags.rb",
41
42
  "lib/id3tag/frames/v2/genre_frame.rb",
42
43
  "lib/id3tag/frames/v2/genre_frame/genre_parser.rb",
43
44
  "lib/id3tag/frames/v2/genre_frame/genre_parser_24.rb",
@@ -67,6 +68,7 @@ Gem::Specification.new do |s|
67
68
  "spec/lib/id3tag/frames/v2/basic_frame_spec.rb",
68
69
  "spec/lib/id3tag/frames/v2/comments_frame_spec.rb",
69
70
  "spec/lib/id3tag/frames/v2/frame_fabricator_spec.rb",
71
+ "spec/lib/id3tag/frames/v2/frame_flags_spec.rb",
70
72
  "spec/lib/id3tag/frames/v2/genre_frame/genre_parser_24_spec.rb",
71
73
  "spec/lib/id3tag/frames/v2/genre_frame/genre_parser_pre_24_spec.rb",
72
74
  "spec/lib/id3tag/frames/v2/genre_frame/genre_parser_spec.rb",
@@ -82,7 +84,12 @@ Gem::Specification.new do |s|
82
84
  "spec/lib/id3tag/synchsafe_integer_spec.rb",
83
85
  "spec/lib/id3tag/tag_spec.rb",
84
86
  "spec/spec_helper.rb",
85
- "spec/support/mp3_fixtures.rb"
87
+ "spec/support/mp3_fixtures.rb",
88
+ "standard_documents/id3v2-00.txt",
89
+ "standard_documents/id3v2.3.0.txt",
90
+ "standard_documents/id3v2.4.0-frames.txt",
91
+ "standard_documents/id3v2.4.0-structure.txt",
92
+ "tags"
86
93
  ]
87
94
  s.homepage = "http://github.com/krists/id3tag"
88
95
  s.licenses = ["MIT"]
data/lib/id3tag.rb CHANGED
@@ -23,6 +23,7 @@ require "id3tag/frames/v2/genre_frame/genre_parser"
23
23
  require "id3tag/frames/v2/genre_frame/genre_parser_pre_24"
24
24
  require "id3tag/frames/v2/genre_frame/genre_parser_24"
25
25
  require "id3tag/frames/v2/frame_fabricator"
26
+ require "id3tag/frames/v2/frame_flags"
26
27
 
27
28
  module ID3Tag
28
29
  def self.read(source, version = :all)
@@ -47,10 +47,14 @@ module ID3Tag
47
47
  version_ids && version_ids[frame_name]
48
48
  end
49
49
 
50
+ def version_of_interest
51
+ "v#{@version}.#{@major_version}"
52
+ end
53
+
50
54
  private
51
55
 
52
56
  def version_ids
53
- COMMON_FRAME_IDS_BY_VERSION["v#{@version}.#{@major_version}"]
57
+ COMMON_FRAME_IDS_BY_VERSION.fetch(version_of_interest)
54
58
  end
55
59
  end
56
60
  end
@@ -2,23 +2,117 @@ module ID3Tag
2
2
  module Frames
3
3
  module V2
4
4
  class BasicFrame
5
- attr_reader :id
5
+ DECOMPRESSED_SIZE_BYTE_COUNT = 4
6
+ GROUP_BYTE_COUNT = 1
7
+
8
+ attr_reader :id, :raw_content
9
+
6
10
  def initialize(id, content, flags, major_version_number)
7
11
  @id, @raw_content, @flags, @major_version_number = id.to_sym, content, flags, major_version_number
8
12
  end
9
13
 
10
14
  def content
11
- @raw_content
15
+ usable_content
16
+ end
17
+
18
+ def usable_content
19
+ raw_content_io.seek(additional_info_byte_count)
20
+ if unsynchronised?
21
+ StringUtil.undo_unsynchronization(raw_content_io.read)
22
+ else
23
+ raw_content_io.read
24
+ end
25
+ end
26
+
27
+ def group_id
28
+ read_additional_info_byte(*position_and_count_of_group_id_bytes) if grouped?
29
+ end
30
+
31
+ def encryption_id
32
+ read_additional_info_byte(*position_and_count_of_encryption_id_bytes) if encrypted?
33
+ end
34
+
35
+ def read_additional_info_byte(position, byte_count)
36
+ if position && byte_count
37
+ raw_content_io.seek(position)
38
+ raw_content_io.read(byte_count).unpack("C").first
39
+ end
40
+ end
41
+
42
+ def final_size
43
+ pos, count = position_and_count_of_data_length_bytes
44
+ if (compressed? || data_length_indicator?) && pos && count
45
+ raw_content_io.seek(pos)
46
+ SynchsafeInteger.decode(NumberUtil.convert_string_to_32bit_integer(raw_content_io.read(count)))
47
+ else
48
+ raw_content_io.size
49
+ end
50
+ end
51
+
52
+ def preserve_on_file_alteration?
53
+ frame_flags.preserve_on_file_alteration?
54
+ end
55
+
56
+ def preserve_on_tag_alteration?
57
+ frame_flags.preserve_on_tag_alteration?
58
+ end
59
+
60
+ def read_only?
61
+ frame_flags.read_only?
62
+ end
63
+
64
+ def compressed?
65
+ frame_flags.compressed?
66
+ end
67
+
68
+ def encrypted?
69
+ frame_flags.encrypted?
70
+ end
71
+
72
+ def grouped?
73
+ frame_flags.grouped?
74
+ end
75
+
76
+ def unsynchronised?
77
+ frame_flags.unsynchronised?
78
+ end
79
+
80
+ def data_length_indicator?
81
+ frame_flags.data_length_indicator?
12
82
  end
13
83
 
14
84
  def inspect
15
- "<#{self.class.name} #{id}: #{inspect_content}>"
85
+ "<#{self.class.name} #{id}: #{inspectable_content}>"
86
+ end
87
+
88
+ def inspectable_content
89
+ content
16
90
  end
17
91
 
18
92
  private
19
93
 
20
- def inspect_content
21
- content
94
+ def additional_info_byte_count
95
+ frame_flags.additional_info_byte_count
96
+ end
97
+
98
+ def position_and_count_of_data_length_bytes
99
+ frame_flags.position_and_count_of_data_length_bytes
100
+ end
101
+
102
+ def position_and_count_of_group_id_bytes
103
+ frame_flags.position_and_count_of_group_id_bytes
104
+ end
105
+
106
+ def position_and_count_of_encryption_id_bytes
107
+ frame_flags.position_and_count_of_encryption_id_bytes
108
+ end
109
+
110
+ def frame_flags
111
+ @frame_flags ||= FrameFlags.new(@flags, @major_version_number)
112
+ end
113
+
114
+ def raw_content_io
115
+ @raw_content_io ||= StringIO.new(raw_content)
22
116
  end
23
117
  end
24
118
  end
@@ -0,0 +1,140 @@
1
+ module ID3Tag
2
+ module Frames
3
+ module V2
4
+ class FrameFlags
5
+ FLAG_MAP_IN_APPEARANCE_ORDER_BY_VERSION = {
6
+ 3 => {
7
+ :status_flags => [ :preserve_on_tag_alteration, :preserve_on_file_alteration, :read_only, nil, nil, nil, nil, nil ],
8
+ :format_flags => [ :compressed, :encrypted, :grouped, nil, nil, nil, nil, nil ]
9
+ },
10
+ 4 => {
11
+ :status_flags => [ nil, :preserve_on_tag_alteration, :preserve_on_file_alteration, :read_only, nil, nil, nil, nil ],
12
+ :format_flags => [ nil, :grouped, nil, nil, :compressed, :encrypted, :unsynchronised, :data_length_indicator ]
13
+ }
14
+ }
15
+
16
+ ADDITIONAL_INFO_BYTES_IN_APPEARANCE_ORDER_BY_VERSION = {
17
+ 3 => [
18
+ [:compressed?, 4], [:encrypted?, 1], [:grouped?, 1]
19
+ ],
20
+ 4 => [
21
+ [:grouped?, 1], [:encrypted?, 1], [:data_length_indicator?, 4]
22
+ ]
23
+ }
24
+
25
+ def initialize(flag_bytes, major_version_number)
26
+ @flag_bytes = flag_bytes
27
+ @major_version_number = major_version_number
28
+ end
29
+
30
+ def preserve_on_tag_alteration?
31
+ flag(:status_flags, :preserve_on_tag_alteration) != 1
32
+ end
33
+
34
+ def preserve_on_file_alteration?
35
+ flag(:status_flags, :preserve_on_file_alteration) != 1
36
+ end
37
+
38
+ def read_only?
39
+ flag(:status_flags, :read_only) == 1
40
+ end
41
+
42
+ def compressed?
43
+ flag(:format_flags, :compressed) == 1
44
+ end
45
+
46
+ def encrypted?
47
+ flag(:format_flags, :encrypted) == 1
48
+ end
49
+
50
+ def grouped?
51
+ flag(:format_flags, :grouped) == 1
52
+ end
53
+
54
+ def unsynchronised?
55
+ flag(:format_flags, :unsynchronised) == 1
56
+ end
57
+
58
+ def data_length_indicator?
59
+ flag(:format_flags, :data_length_indicator) == 1
60
+ end
61
+
62
+ def additional_info_byte_count
63
+ additional_info_flags_in_effect.inject(0) do |total, query|
64
+ total += query.last
65
+ total
66
+ end
67
+ end
68
+
69
+ def position_and_count_of_data_length_bytes
70
+ if data_length_indicator? || compressed?
71
+ find_position_and_length_for_additional_info(:data_length_indicator?, :compressed?)
72
+ end
73
+ end
74
+
75
+ def position_and_count_of_group_id_bytes
76
+ if grouped?
77
+ find_position_and_length_for_additional_info(:grouped?)
78
+ end
79
+ end
80
+
81
+ def position_and_count_of_encryption_id_bytes
82
+ if encrypted?
83
+ find_position_and_length_for_additional_info(:encrypted?)
84
+ end
85
+ end
86
+
87
+ def find_position_and_length_for_additional_info(*methods_of_interest)
88
+ start_position = 0
89
+ target_info_byte_count = nil
90
+ additional_info_flags_in_effect.map do |query_method, byte_count|
91
+ start_position += (byte_count) unless methods_of_interest.include?(query_method)
92
+ if methods_of_interest.include?(query_method)
93
+ target_info_byte_count = byte_count
94
+ break
95
+ end
96
+ end
97
+ [start_position, target_info_byte_count]
98
+ end
99
+
100
+ def additional_info_flags_in_effect
101
+ current_additional_info_map.reject { |q| !self.send(q.first) }
102
+ end
103
+
104
+ private
105
+
106
+ def flag(scope, name)
107
+ index = index_of_flag(scope, name)
108
+ if index
109
+ flags = flags_for_scope(scope)
110
+ flags && flags[7 - index]
111
+ end
112
+ end
113
+
114
+ def flags_for_scope(scope)
115
+ pair = @flag_bytes.to_s.unpack("C2")
116
+ case scope
117
+ when :status_flags
118
+ pair.first
119
+ when :format_flags
120
+ pair.last
121
+ end
122
+ end
123
+
124
+ def index_of_flag(scope, name)
125
+ current_flag_map[scope].find_index(name)
126
+ end
127
+
128
+ def current_flag_map
129
+ FLAG_MAP_IN_APPEARANCE_ORDER_BY_VERSION.fetch(@major_version_number) do
130
+ { :status_flags => [], :format_flags => [] }
131
+ end
132
+ end
133
+
134
+ def current_additional_info_map
135
+ ADDITIONAL_INFO_BYTES_IN_APPEARANCE_ORDER_BY_VERSION.fetch(@major_version_number) { [] }
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end