ogg_album_tagger 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,75 @@
1
+ require 'shellwords'
2
+ require 'set'
3
+ require 'taglib'
4
+ require 'ogg_album_tagger/exceptions'
5
+ require 'ogg_album_tagger/tag_container'
6
+
7
+ module OggAlbumTagger
8
+
9
+ # Store the tags of an ogg track.
10
+ #
11
+ # Each tag is associated to a Set of values.
12
+ class OggFile < OggAlbumTagger::TagContainer
13
+ attr_accessor :path
14
+
15
+ # Initialize a TagContainer from an ogg file.
16
+ def initialize(file)
17
+ begin
18
+ h = Hash.new
19
+
20
+ TagLib::Ogg::Vorbis::File.open(file.to_s) do |ogg|
21
+ ogg.tag.field_list_map.each do |tag, values|
22
+ h[tag] = Set.new
23
+ values.each do |value|
24
+ h[tag].add(value.strip)
25
+ end
26
+ end
27
+ end
28
+
29
+ super(h)
30
+ @path = file
31
+ rescue Exception => ex
32
+ STDERR.puts ex
33
+ raise OggAlbumTagger::ArgumentError, "#{file} does not seems to be a valid ogg file."
34
+ end
35
+ end
36
+
37
+ # Write the tags in the specified file.
38
+ def write(file)
39
+ begin
40
+ TagLib::Ogg::Vorbis::File.open(file.to_s) do |ogg|
41
+ tags = ogg.tag
42
+
43
+ # Remove old tags
44
+ tags.field_list_map.keys.each { |t| tags.remove_field(t) }
45
+
46
+ # Set new tags (Taglib will write them sorted)
47
+ @hash.each do |tag, values|
48
+ values.sort.each do |v|
49
+ tags.add_field(tag, v, false)
50
+ end
51
+ end
52
+
53
+ # Save everything
54
+ ogg.save
55
+ end
56
+ rescue Exception
57
+ raise OggAlbumTagger::ArgumentError, "#{file} cannot be written."
58
+ end
59
+ end
60
+
61
+ def to_s
62
+ OggFile.sorted_tags(@hash.keys).map do |tag|
63
+ OggFile.pp_tag(@hash[tag])
64
+ end.join "\n"
65
+ end
66
+
67
+ # Sort the tag keys alphabetically, but put METADATA_BLOCK_PICTURE at the end.
68
+ def self.sorted_tags(tags)
69
+ a = tags.sort
70
+ a.delete('METADATA_BLOCK_PICTURE') and a.push('METADATA_BLOCK_PICTURE')
71
+ block_given? ? a.each { |v| yield v } : a
72
+ end
73
+ end
74
+
75
+ end # module OggAlbumTagger
@@ -1,151 +1,127 @@
1
1
  require 'shellwords'
2
2
  require 'set'
3
3
  require 'ogg_album_tagger/exceptions'
4
- require 'taglib'
5
4
 
6
5
  module OggAlbumTagger
7
6
 
8
- # Store the tags of an ogg track.
7
+ # A TagContainer is basically a hashmap associating a name to a set of string values.
9
8
  #
10
- # Each tag is associated to a Set of values.
9
+ # The keys of the hashmap (aka the tags) are case insensitive (they are stored upcase).
10
+ # A tag cannot be an empty string or containe the "=" or "~" characters.
11
+ # Tags with no values are automatically removed.
11
12
  class TagContainer
12
- # Initialize a TagContainer from an ogg file.
13
- def initialize(file)
14
- @hash = Hash.new
15
-
16
- begin
17
- TagLib::Ogg::Vorbis::File.open(file.to_s) do |ogg|
18
- ogg.tag.field_list_map.each do |tag, values|
19
- prepare_tag(tag.upcase)
20
-
21
- values.each do |value|
22
- @hash[tag.upcase].add(value.strip)
23
- end
24
- end
25
- end
26
- rescue Exception => ex
27
- #STDERR.puts ex
28
- raise OggAlbumTagger::ArgumentError, "#{file} does not seems to be a valid ogg file."
29
- end
30
- end
31
-
32
- # Write the tags in the specified file.
33
- def write(file)
34
- begin
35
- TagLib::Ogg::Vorbis::File.open(file.to_s) do |ogg|
36
- tags = ogg.tag
37
-
38
- # Remove old tags
39
- tags.field_list_map.keys.each { |t| tags.remove_field(t) }
40
-
41
- # Set new tags (Taglib will write them sorted)
42
- @hash.each do |tag, values|
43
- values.sort.each do |v|
44
- tags.add_field(tag, v, false)
45
- end
46
- end
47
-
48
- # Save everything
49
- ogg.save
50
- end
51
- rescue Exception => ex
52
- #STDERR.puts ex
53
- raise OggAlbumTagger::ArgumentError, "#{file} cannot be written."
54
- end
55
- end
56
-
57
- # Returns a Set containing the values associated to the specified tag.
58
- #
59
- # If the tag does not exists, returns an empty Set.
60
- # Do not use the returned Set to add new tags, use the methods provided by the class.
61
- def [](tag)
62
- has_tag?(tag) ? @hash[tag.upcase] : Set.new.freeze
63
- end
64
-
65
- def first(tag)
66
- if has_tag?(tag)
67
- return @hash[tag.upcase].first
68
- else
69
- raise IndexError, "Tag \"#{tag}\" does not exists."
70
- end
71
- end
72
-
73
- # Check if the specified tag is present in the container.
74
- def has_tag? tag
75
- @hash.has_key?(tag.upcase)
76
- end
77
-
78
- # Check if the tag is valid, otherwise raise an ArgulentError.
79
- def valid_tag? tag
80
- raise ArgumentError, "Invalid tag." unless tag =~ /^[\x20-\x3C\x3E-\x7D]+$/
81
- end
82
-
83
- # If the specified tag is absent from the container, associate an empty Set to it.
84
- def prepare_tag tag
85
- valid_tag? tag
86
- @hash[tag.upcase] = Set.new unless self.has_tag?(tag)
87
- end
88
-
89
- # Add some values to the specified tag.
90
- # Any previous values will be removed.
91
- def set_values(tag, *values)
92
- prepare_tag tag
93
- @hash[tag.upcase].replace(values)
94
- end
95
-
96
- # Add some values to the specified tag.
97
- def add_values(tag, *values)
98
- prepare_tag tag
99
- @hash[tag.upcase].merge(values)
100
- end
101
-
102
- # Remove some tags. If no value is specified, the specified tag is removed.
103
- def rm_values(tag, *values)
104
- valid_tag? tag
105
-
106
- if values.empty? then @hash.delete(tag.upcase)
107
- else
108
- @hash[tag.upcase].subtract(values)
109
- @hash.delete(tag.upcase) if @hash[tag.upcase].empty?
110
- end
111
- end
112
-
113
- # Returns the list of present tags.
114
- def tags
115
- @hash.keys
116
- end
117
-
118
- # Iterate through the available tags.
119
- def each
120
- @hash.each { |tag, set| yield(tag, set) }
121
- end
122
-
123
- def to_s
124
- TagContainer.sorted_tags(@hash.keys).map do |tag|
125
- TagContainer.pp_tag(@hash[tag])
126
- end.join "\n"
127
- end
128
-
129
- # Sort the tag keys alphabetically, but put METADATA_BLOCK_PICTURE at the end.
130
- def self.sorted_tags(tags)
131
- a = tags.sort
132
- a.delete('METADATA_BLOCK_PICTURE') and a.push('METADATA_BLOCK_PICTURE')
133
- block_given? ? a.each { |v| yield v } : a
134
- end
135
-
136
- # Pretty print an array of values.
137
- def self.pp_tag values
138
- values_str = values.map { |v| v.to_s.length > 64 ? (v.to_s.slice(0, 64) + '...') : v }
139
-
140
- case values.length
141
- when 0 then '- (empty)'
142
- when 1 then values_str[0]
143
- else sprintf("(%d) [%s]", values.length, values_str.join(', '))
144
- end
145
- end
146
-
147
- private :prepare_tag
148
- private :valid_tag?
13
+ # Allow to build a TagContainer using the following syntax:
14
+ #
15
+ # <tt>t = TagContainer.new artist: "Alice", genre: %w{Pop Rock}, tracknumber: 1, ...</tt>
16
+ # The values associated to a tag are automatically casted to a String.
17
+ # Single values are treated as an array of one value.
18
+ def initialize tags = {}
19
+ @hash = Hash.new
20
+
21
+ tags.each { |tag, values|
22
+ next if values.nil?
23
+
24
+ values = [values] unless values.is_a?(Array) or values.is_a?(Set)
25
+
26
+ next if values.empty?
27
+
28
+ prepare_tag(tag.to_s.upcase)
29
+ values.each { |value| @hash[tag.to_s.upcase].add(value.to_s) }
30
+ }
31
+ end
32
+
33
+ # Returns a Set containing the values associated to the specified tag.
34
+ #
35
+ # If the tag does not exists, returns an empty Set.
36
+ # Do not use the returned Set to add new tags, use the methods provided by the class.
37
+ def [](tag)
38
+ has_tag?(tag) ? @hash[tag.upcase] : Set.new.freeze
39
+ end
40
+
41
+ def first(tag)
42
+ if has_tag?(tag)
43
+ return @hash[tag.upcase].first
44
+ else
45
+ raise IndexError, "Tag \"#{tag}\" does not exists."
46
+ end
47
+ end
48
+
49
+ # Check if the specified tag is present in the container.
50
+ def has_tag? tag
51
+ @hash.has_key?(tag.upcase)
52
+ end
53
+
54
+ # Check if the tag is valid, otherwise raise an ArgumentError.
55
+ # Valid tags are composed of any character from " " to "}", excluding "=" and "~".
56
+ def self.valid_tag? tag
57
+ raise ArgumentError, "Invalid tag." unless tag =~ /^[\x20-\x3C\x3E-\x7D]+$/
58
+ end
59
+
60
+ # If the specified tag is absent from the container, associate an empty Set to it.
61
+ def prepare_tag tag
62
+ TagContainer::valid_tag? tag
63
+ @hash[tag.upcase] = Set.new unless self.has_tag?(tag)
64
+ end
65
+
66
+ # Add some values to the specified tag.
67
+ # Any previous values will be removed.
68
+ def set_values(tag, *values)
69
+ if values.empty?
70
+ rm_values(tag)
71
+ else
72
+ prepare_tag tag
73
+ @hash[tag.upcase].replace(values)
74
+ end
75
+
76
+ self
77
+ end
78
+
79
+ # Add some values to the specified tag.
80
+ def add_values(tag, *values)
81
+ return if values.empty?
82
+
83
+ prepare_tag tag
84
+ @hash[tag.upcase].merge(values)
85
+
86
+ self
87
+ end
88
+
89
+ # Remove some tags. If no value is specified, the specified tag is removed.
90
+ def rm_values(tag, *values)
91
+ TagContainer::valid_tag? tag
92
+
93
+ if values.empty?
94
+ @hash.delete(tag.upcase)
95
+ else
96
+ @hash[tag.upcase].subtract(values)
97
+ @hash.delete(tag.upcase) if @hash[tag.upcase].empty?
98
+ end
99
+
100
+ self
101
+ end
102
+
103
+ # Returns the list of present tags.
104
+ def tags
105
+ @hash.keys
106
+ end
107
+
108
+ # Iterate through the available tags.
109
+ def each
110
+ @hash.each { |tag, set| yield(tag, set) }
111
+ end
112
+
113
+ # Pretty print an array of values.
114
+ def self.pp_tag values
115
+ values_str = values.map { |v| v.to_s.length > 64 ? (v.to_s.slice(0, 64) + '...') : v }
116
+
117
+ case values.length
118
+ when 0 then '- (empty)'
119
+ when 1 then values_str[0]
120
+ else sprintf("(%d) [%s]", values.length, values_str.join(', '))
121
+ end
122
+ end
123
+
124
+ private :prepare_tag
149
125
  end
150
126
 
151
- end
127
+ end # module OggAlbumTagger
@@ -1,3 +1,3 @@
1
1
  module OggAlbumTagger
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ogg_album_tagger
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cyrille Faucheux
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-01 00:00:00.000000000 Z
11
+ date: 2018-04-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,28 +16,56 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.7'
19
+ version: '1.16'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.7'
26
+ version: '1.16'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '12.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '12.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.11'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.11'
55
+ - !ruby/object:Gem::Dependency
56
+ name: m
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.5'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.5'
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: exiftool
43
71
  requirement: !ruby/object:Gem::Requirement
@@ -75,8 +103,10 @@ extensions: []
75
103
  extra_rdoc_files: []
76
104
  files:
77
105
  - bin/ogg-album-tagger
106
+ - lib/ogg_album_tagger/cli.rb
78
107
  - lib/ogg_album_tagger/exceptions.rb
79
108
  - lib/ogg_album_tagger/library.rb
109
+ - lib/ogg_album_tagger/ogg_file.rb
80
110
  - lib/ogg_album_tagger/picture.rb
81
111
  - lib/ogg_album_tagger/tag_container.rb
82
112
  - lib/ogg_album_tagger/version.rb
@@ -100,7 +130,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
130
  version: '0'
101
131
  requirements: []
102
132
  rubyforge_project:
103
- rubygems_version: 2.4.6
133
+ rubygems_version: 2.5.2.1
104
134
  signing_key:
105
135
  specification_version: 4
106
136
  summary: Interactive edition of ogg tags with support for whole albums.