id3tag 0.1.1 → 0.2.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.
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