id3_tags 0.0.1
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.
- data/.gitignore +16 -0
- data/.rspec +1 -0
- data/Gemfile +6 -0
- data/HISTORY.md +1 -0
- data/MIT-LICENSE +20 -0
- data/README.md +32 -0
- data/Rakefile +12 -0
- data/TODO.md +2 -0
- data/doc/Id3Tags.html +495 -0
- data/doc/_index.html +110 -0
- data/doc/class_list.html +53 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +57 -0
- data/doc/css/style.css +338 -0
- data/doc/file.README.html +102 -0
- data/doc/file_list.html +55 -0
- data/doc/frames.html +28 -0
- data/doc/index.html +102 -0
- data/doc/js/app.js +214 -0
- data/doc/js/full_list.js +178 -0
- data/doc/js/jquery.js +4 -0
- data/doc/method_list.html +64 -0
- data/doc/top-level-namespace.html +112 -0
- data/id3_tags.gemspec +30 -0
- data/lib/id3_tags/version.rb +3 -0
- data/lib/id3_tags.rb +182 -0
- data/spec/assets/all_id3.mp3 +0 -0
- data/spec/assets/black_pixel.png +0 -0
- data/spec/assets/no_id3.mp3 +0 -0
- data/spec/helpers/duplicate_file_helper.rb +11 -0
- data/spec/lib/idempotency_spec.rb +14 -0
- data/spec/lib/read_id3_tags_spec.rb +72 -0
- data/spec/lib/write_id3_tags_spec.rb +67 -0
- metadata +207 -0
data/lib/id3_tags.rb
ADDED
@@ -0,0 +1,182 @@
|
|
1
|
+
require 'taglib'
|
2
|
+
require 'active_support/core_ext/hash'
|
3
|
+
|
4
|
+
# Provides two methods to read and write ID3 metadata from an MP3 file
|
5
|
+
module Id3Tags
|
6
|
+
|
7
|
+
# Returns a Hash of ID3 attributes stored in the file located at +file_path+.
|
8
|
+
#
|
9
|
+
# @param [String] file_path Local path to an MP3 file
|
10
|
+
# @return [Hash] the ID3 attributes stored in the file
|
11
|
+
#
|
12
|
+
# @example Read tags from an MP3 full of metadata
|
13
|
+
# Id3Tags.read_tags_from("all_id3.mp3")
|
14
|
+
#
|
15
|
+
# # => {title: "Sample track", album: "Sample album", artist: Sample
|
16
|
+
# artist", :comment=>"Sample comments", genre: "Sample Genre",
|
17
|
+
# year: 1979, bitrate: 128, channels: 2, length: 38, samplerate:
|
18
|
+
# 44100, bpm: 110, lyrics: "Sample lyrics line 1\rand line 2",
|
19
|
+
# composer: "Sample composer", grouping: "Sample group",
|
20
|
+
# album_artist: "Sample album artist", compilation: true, track:
|
21
|
+
# {number: 3, count: 12}, disk: {number: 1, count: 2}, cover_art:
|
22
|
+
# {mime_type: "image/png", data: "\x89PNG\r\n\x1A[...]"}}
|
23
|
+
def self.read_tags_from(file_path)
|
24
|
+
attrs = {}
|
25
|
+
TagLib::MPEG::File.open(file_path) do |file|
|
26
|
+
tag_fields.each do |field, opts|
|
27
|
+
value = file.tag.send opts[:method]
|
28
|
+
assign! attrs, field, value, opts[:type]
|
29
|
+
end unless file.tag.nil?
|
30
|
+
|
31
|
+
audio_properties_fields.each do |field, opts|
|
32
|
+
value = file.audio_properties.send opts[:method]
|
33
|
+
assign! attrs, field, value, opts[:type]
|
34
|
+
end unless file.audio_properties.nil?
|
35
|
+
|
36
|
+
id3v2_tag_fields.each do |field, opts|
|
37
|
+
value = file.id3v2_tag.frame_list(opts[:frame_id]).first
|
38
|
+
value = value.to_string if value and opts[:type] != :image
|
39
|
+
assign! attrs, field, value, opts[:type]
|
40
|
+
end unless file.id3v2_tag.nil?
|
41
|
+
end
|
42
|
+
|
43
|
+
attrs.symbolize_keys
|
44
|
+
end
|
45
|
+
|
46
|
+
# Stores the +attrs+ Hash of ID3 attributes into the file at +file_path+.
|
47
|
+
#
|
48
|
+
# @param [String] file_path Local path to an MP3 file
|
49
|
+
# @param [Hash] attrs the ID3 attributes stored in the file
|
50
|
+
# @return [Boolean] true (the file gets changed)
|
51
|
+
#
|
52
|
+
# @example Write ID3 tags to an MP3 file
|
53
|
+
# Id3Tags.write_tags_to("no_id3.mp3", {title: "Sample track", album:
|
54
|
+
# "Sample album", artist: Sample artist", :comment=>"Sample comments",
|
55
|
+
# genre: "Sample Genre", year: 1979, bitrate: 128, channels: 2,
|
56
|
+
# length: 38, samplerate: 44100, bpm: 110, lyrics: "Sample lyrics
|
57
|
+
# line 1\rand line 2", composer: "Sample composer", grouping: "Sample
|
58
|
+
# group", album_artist: "Sample album artist", compilation: true,
|
59
|
+
# track: {number: 3, count: 12}, disk: {number: 1, count: 2},
|
60
|
+
# cover_art: {mime_type: "image/png", data: "\x89PNG\r\n\x1A[...]"}}
|
61
|
+
#
|
62
|
+
# # => true
|
63
|
+
def self.write_tags_to(file_path, attrs = {})
|
64
|
+
attrs.symbolize_keys!
|
65
|
+
|
66
|
+
TagLib::MPEG::File.open(file_path) do |file|
|
67
|
+
tag_fields.each do |field, opts|
|
68
|
+
file.tag.send "#{opts[:method]}=", (attrs[field] || opts[:default])
|
69
|
+
end unless file.tag.nil?
|
70
|
+
|
71
|
+
id3v2_tag_fields.each do |field, opts|
|
72
|
+
file.id3v2_tag.remove_frames opts[:frame_id]
|
73
|
+
frame = new_frame_for attrs[field], opts[:frame_id], opts[:type]
|
74
|
+
file.id3v2_tag.add_frame frame if frame
|
75
|
+
end unless file.id3v2_tag.nil?
|
76
|
+
|
77
|
+
file.save
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# @private
|
82
|
+
def self.fields
|
83
|
+
{
|
84
|
+
title: {on: :tag, method: :title, type: :string},
|
85
|
+
album: {on: :tag, method: :album, type: :string},
|
86
|
+
artist: {on: :tag, method: :artist, type: :string},
|
87
|
+
comment: {on: :tag, method: :comment, type: :string},
|
88
|
+
genre: {on: :tag, method: :genre, type: :string},
|
89
|
+
year: {on: :tag, method: :year, type: :integer, default: 0},
|
90
|
+
bitrate: {on: :audio_properties, method: :bitrate, type: :integer},
|
91
|
+
channels: {on: :audio_properties, method: :channels, type: :integer},
|
92
|
+
length: {on: :audio_properties, method: :length, type: :integer},
|
93
|
+
samplerate: {on: :audio_properties, method: :sample_rate, type: :integer},
|
94
|
+
bpm: {on: :id3v2_tag, frame_id: 'TBPM', type: :integer},
|
95
|
+
lyrics: {on: :id3v2_tag, frame_id: 'USLT', type: :text},
|
96
|
+
composer: {on: :id3v2_tag, frame_id: 'TCOM', type: :string},
|
97
|
+
grouping: {on: :id3v2_tag, frame_id: 'TIT1', type: :string},
|
98
|
+
album_artist:{on: :id3v2_tag, frame_id: 'TPE2', type: :string},
|
99
|
+
compilation: {on: :id3v2_tag, frame_id: 'TCMP', type: :boolean},
|
100
|
+
track: {on: :id3v2_tag, frame_id: 'TRCK', type: :pair},
|
101
|
+
disk: {on: :id3v2_tag, frame_id: 'TPOS', type: :pair},
|
102
|
+
cover_art: {on: :id3v2_tag, frame_id: 'APIC', type: :image},
|
103
|
+
}
|
104
|
+
end
|
105
|
+
|
106
|
+
# @private
|
107
|
+
def self.tag_fields
|
108
|
+
fields.select{|k,v| v[:on] == :tag}
|
109
|
+
end
|
110
|
+
|
111
|
+
# @private
|
112
|
+
def self.audio_properties_fields
|
113
|
+
fields.select{|k,v| v[:on] == :audio_properties }
|
114
|
+
end
|
115
|
+
|
116
|
+
# @private
|
117
|
+
def self.id3v2_tag_fields
|
118
|
+
fields.select{|k,v| v[:on] == :id3v2_tag }
|
119
|
+
end
|
120
|
+
|
121
|
+
# @private
|
122
|
+
def self.assign!(attrs, field, value, type)
|
123
|
+
case type
|
124
|
+
when :string, :text
|
125
|
+
attrs[field] = value && value.to_s
|
126
|
+
when :integer
|
127
|
+
attrs[field] = value && value.to_i
|
128
|
+
when :boolean
|
129
|
+
attrs[field] = value.present? && value.eql?('1')
|
130
|
+
when :pair
|
131
|
+
pair = value ? value.split('/').map(&:to_i) : [nil, nil]
|
132
|
+
attrs[field] = {number: pair[0], count: pair[1]}
|
133
|
+
when :image
|
134
|
+
pair = [value && value.mime_type, value && value.picture].map(&:presence)
|
135
|
+
attrs[field] = {mime_type: pair[0], data: pair[1]}
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# @private
|
140
|
+
def self.new_frame_for(content, frame_id, type)
|
141
|
+
return if content.nil?
|
142
|
+
case type
|
143
|
+
when :string, :integer
|
144
|
+
frame = new_string_frame(frame_id)
|
145
|
+
frame.text = content.to_s
|
146
|
+
when :text
|
147
|
+
frame = new_text_frame(frame_id)
|
148
|
+
frame.text = content.to_s
|
149
|
+
when :boolean
|
150
|
+
return unless content.eql?(true)
|
151
|
+
frame = new_string_frame(frame_id)
|
152
|
+
frame.text = '1'
|
153
|
+
when :pair
|
154
|
+
return unless content.has_key? :number
|
155
|
+
frame = new_string_frame(frame_id)
|
156
|
+
frame.text = content.values_at(:number, :count).compact.join '/'
|
157
|
+
when :image
|
158
|
+
return unless content.has_key? :data
|
159
|
+
frame = new_image_frame(frame_id)
|
160
|
+
frame.description = 'Cover'
|
161
|
+
frame.type = TagLib::ID3v2::AttachedPictureFrame::FrontCover
|
162
|
+
frame.mime_type = content[:mime_type]
|
163
|
+
frame.picture = content[:data]
|
164
|
+
end
|
165
|
+
frame
|
166
|
+
end
|
167
|
+
|
168
|
+
# @private
|
169
|
+
def self.new_string_frame(frame_id)
|
170
|
+
TagLib::ID3v2::TextIdentificationFrame.new frame_id, TagLib::String::UTF8
|
171
|
+
end
|
172
|
+
|
173
|
+
# @private
|
174
|
+
def self.new_text_frame(frame_id)
|
175
|
+
TagLib::ID3v2::UnsynchronizedLyricsFrame.new frame_id
|
176
|
+
end
|
177
|
+
|
178
|
+
# @private
|
179
|
+
def self.new_image_frame(frame_id)
|
180
|
+
TagLib::ID3v2::AttachedPictureFrame.new frame_id
|
181
|
+
end
|
182
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'id3_tags'
|
2
|
+
require_relative '../helpers/duplicate_file_helper'
|
3
|
+
|
4
|
+
describe Id3Tags do
|
5
|
+
it 'does not alter tracks after reading AND writing the metadata' do
|
6
|
+
original = File.join File.dirname(__FILE__), '../assets/all_id3.mp3'
|
7
|
+
original_id3_tags = Id3Tags.read_tags_from(original)
|
8
|
+
with_duplicate_file_of(original) do |duplicate|
|
9
|
+
Id3Tags.write_tags_to(duplicate, original_id3_tags)
|
10
|
+
Id3Tags.read_tags_from(duplicate).should == original_id3_tags
|
11
|
+
FileUtils.identical?(original, duplicate).should be_true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'id3_tags'
|
2
|
+
|
3
|
+
describe 'Id3Tags.read_tags_from' do
|
4
|
+
context 'given a track with all the ID3 metadata' do
|
5
|
+
let(:track_with_metadata) {File.join File.dirname(__FILE__), '../assets/all_id3.mp3'}
|
6
|
+
|
7
|
+
it 'returns all the ID3 tag with the right value' do
|
8
|
+
id3_tags = Id3Tags.read_tags_from track_with_metadata
|
9
|
+
|
10
|
+
id3_tags.keys.should =~ [:album, :artist, :comment, :genre, :samplerate,
|
11
|
+
:track, :disk, :title, :year, :bitrate, :channels, :length, :grouping,
|
12
|
+
:album_artist, :composer, :bpm, :lyrics, :compilation, :cover_art]
|
13
|
+
id3_tags[:title].should == 'Sample track'
|
14
|
+
id3_tags[:album].should == 'Sample album'
|
15
|
+
id3_tags[:artist].should == 'Sample artist'
|
16
|
+
id3_tags[:comment].should == 'Sample comments'
|
17
|
+
id3_tags[:genre].should == 'Sample Genre'
|
18
|
+
id3_tags[:year].should == 1979
|
19
|
+
id3_tags[:track][:number].should == 3
|
20
|
+
id3_tags[:track][:count].should == 12
|
21
|
+
id3_tags[:disk][:number].should == 1
|
22
|
+
id3_tags[:disk][:count].should == 2
|
23
|
+
id3_tags[:bitrate].should == 128
|
24
|
+
id3_tags[:channels].should == 2
|
25
|
+
id3_tags[:length].should == 38
|
26
|
+
id3_tags[:samplerate].should == 44100
|
27
|
+
id3_tags[:album_artist].should == 'Sample album artist'
|
28
|
+
id3_tags[:composer].should == 'Sample composer'
|
29
|
+
id3_tags[:grouping].should == 'Sample group'
|
30
|
+
id3_tags[:bpm].should == 110
|
31
|
+
id3_tags[:lyrics].should == "Sample lyrics line 1\rand line 2"
|
32
|
+
id3_tags[:compilation].should be_true
|
33
|
+
id3_tags[:cover_art][:mime_type].should == 'image/png'
|
34
|
+
id3_tags[:cover_art][:data].length.should == 3368
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'given a track with no ID3 metadata' do
|
39
|
+
let(:track_with_metadata) {File.join File.dirname(__FILE__), '../assets/no_id3.mp3'}
|
40
|
+
|
41
|
+
it 'returns all the ID3 tag with a nil value' do
|
42
|
+
id3_tags = Id3Tags.read_tags_from track_with_metadata
|
43
|
+
|
44
|
+
id3_tags.keys.should =~ [:album, :artist, :comment, :genre, :samplerate,
|
45
|
+
:track, :disk, :title, :year, :bitrate, :channels, :length, :grouping,
|
46
|
+
:album_artist, :composer, :bpm, :lyrics, :compilation, :cover_art]
|
47
|
+
|
48
|
+
id3_tags[:title].should == ' ' # can never be nil
|
49
|
+
id3_tags[:album].should be_nil
|
50
|
+
id3_tags[:artist].should be_nil
|
51
|
+
id3_tags[:comment].should be_nil
|
52
|
+
id3_tags[:genre].should be_nil
|
53
|
+
id3_tags[:year].should == 0 # can never be nil
|
54
|
+
id3_tags[:track][:number].should be_nil
|
55
|
+
id3_tags[:track][:count].should be_nil
|
56
|
+
id3_tags[:disk][:number].should be_nil
|
57
|
+
id3_tags[:disk][:count].should be_nil
|
58
|
+
id3_tags[:bitrate].should == 128 # can never be nil
|
59
|
+
id3_tags[:channels].should == 2 # can never be nil
|
60
|
+
id3_tags[:length].should == 38 # can never be nil
|
61
|
+
id3_tags[:samplerate].should == 44100 # can never be nil
|
62
|
+
id3_tags[:album_artist].should be_nil
|
63
|
+
id3_tags[:composer].should be_nil
|
64
|
+
id3_tags[:grouping].should be_nil
|
65
|
+
id3_tags[:bpm].should be_nil
|
66
|
+
id3_tags[:lyrics].should be_nil
|
67
|
+
id3_tags[:compilation].should be_false
|
68
|
+
id3_tags[:cover_art][:mime_type].should be_nil
|
69
|
+
id3_tags[:cover_art][:data].should be_nil
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'id3_tags'
|
2
|
+
require_relative '../helpers/duplicate_file_helper'
|
3
|
+
|
4
|
+
describe 'Id3Tags.write_tags_to' do
|
5
|
+
context 'given a track with all the ID3 metadata and a Hash of empty ID3' do
|
6
|
+
let(:original_track) {File.join File.dirname(__FILE__), '../assets/all_id3.mp3'}
|
7
|
+
let(:new_metadata) { {} }
|
8
|
+
|
9
|
+
it 'resets all the editable ID3 tags of the track to nil' do
|
10
|
+
with_duplicate_file_of(original_track) do |duplicate|
|
11
|
+
Id3Tags.write_tags_to(duplicate, new_metadata)
|
12
|
+
id3_tags = Id3Tags.read_tags_from(duplicate)
|
13
|
+
[:album, :artist, :comment, :genre, :title, :grouping, :lyrics,
|
14
|
+
:album_artist, :composer, :bpm].each do |field|
|
15
|
+
id3_tags[field].should be_nil
|
16
|
+
end
|
17
|
+
id3_tags[:year].should == 0
|
18
|
+
id3_tags[:compilation].should be_false
|
19
|
+
# NOTE: Taglib does NOT allow the track_number to be nil; the old
|
20
|
+
# value is persisted in this case, so we cannot test for nil?
|
21
|
+
#id3_tags[:track][:number].should be_nil
|
22
|
+
id3_tags[:track][:count].should be_nil
|
23
|
+
id3_tags[:disk][:number].should be_nil
|
24
|
+
id3_tags[:disk][:count].should be_nil
|
25
|
+
id3_tags[:cover_art][:mime_type].should be_nil
|
26
|
+
id3_tags[:cover_art][:data].should be_nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'given a track with no metadata and a Hash full of ID3' do
|
32
|
+
let(:original_track) {File.join File.dirname(__FILE__), '../assets/no_id3.mp3'}
|
33
|
+
let(:new_cover_art) {File.join File.dirname(__FILE__), '../assets/black_pixel.png'}
|
34
|
+
let(:new_cover_art_data) {File.open(new_cover_art, 'rb') {|io| io.read}}
|
35
|
+
let(:new_metadata) { {title: "A track", album: "An album", artist:
|
36
|
+
"An artist", year: 2012, comment: "A comment", genre: "A genre", bpm: 68,
|
37
|
+
composer: "A composer", lyrics: "A lyrics line 1\rand line 2",
|
38
|
+
album_artist: "An album artist", grouping: "A group", compilation: true,
|
39
|
+
track: {number: 1, count: 24}, disk: {number: 1, count: 2}, cover_art:
|
40
|
+
{mime_type: "image/png", data: new_cover_art_data}}
|
41
|
+
}
|
42
|
+
|
43
|
+
it 'sets all the editable ID3 tags of a track' do
|
44
|
+
with_duplicate_file_of(original_track) do |duplicate|
|
45
|
+
Id3Tags.write_tags_to(duplicate, new_metadata)
|
46
|
+
id3_tags = Id3Tags.read_tags_from(duplicate)
|
47
|
+
id3_tags[:album].should == 'An album'
|
48
|
+
id3_tags[:artist].should == 'An artist'
|
49
|
+
id3_tags[:comment].should == 'A comment'
|
50
|
+
id3_tags[:genre].should == 'A genre'
|
51
|
+
id3_tags[:title].should == 'A track'
|
52
|
+
id3_tags[:grouping].should == 'A group'
|
53
|
+
id3_tags[:lyrics].should == "A lyrics line 1\rand line 2"
|
54
|
+
id3_tags[:album_artist].should == 'An album artist'
|
55
|
+
id3_tags[:composer].should == 'A composer'
|
56
|
+
id3_tags[:bpm].should == 68
|
57
|
+
id3_tags[:compilation].should be_true
|
58
|
+
id3_tags[:track][:number].should == 1
|
59
|
+
id3_tags[:track][:count].should == 24
|
60
|
+
id3_tags[:disk][:number].should == 1
|
61
|
+
id3_tags[:disk][:count].should == 2
|
62
|
+
id3_tags[:cover_art][:mime_type].should == 'image/png'
|
63
|
+
id3_tags[:cover_art][:data].should == new_cover_art_data
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
metadata
ADDED
@@ -0,0 +1,207 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: id3_tags
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Claudio Baccigalupo
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-06-14 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: taglib-ruby
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: activesupport
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: bundler
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.3'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.3'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rake
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rspec
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: redcarpet
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: yard
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
description: Read and write ID3 metadata from/to MP3 files
|
127
|
+
email:
|
128
|
+
- claudio@topspinmedia.com
|
129
|
+
executables: []
|
130
|
+
extensions: []
|
131
|
+
extra_rdoc_files: []
|
132
|
+
files:
|
133
|
+
- .gitignore
|
134
|
+
- .rspec
|
135
|
+
- Gemfile
|
136
|
+
- HISTORY.md
|
137
|
+
- MIT-LICENSE
|
138
|
+
- README.md
|
139
|
+
- Rakefile
|
140
|
+
- TODO.md
|
141
|
+
- doc/Id3Tags.html
|
142
|
+
- doc/_index.html
|
143
|
+
- doc/class_list.html
|
144
|
+
- doc/css/common.css
|
145
|
+
- doc/css/full_list.css
|
146
|
+
- doc/css/style.css
|
147
|
+
- doc/file.README.html
|
148
|
+
- doc/file_list.html
|
149
|
+
- doc/frames.html
|
150
|
+
- doc/index.html
|
151
|
+
- doc/js/app.js
|
152
|
+
- doc/js/full_list.js
|
153
|
+
- doc/js/jquery.js
|
154
|
+
- doc/method_list.html
|
155
|
+
- doc/top-level-namespace.html
|
156
|
+
- id3_tags.gemspec
|
157
|
+
- lib/id3_tags.rb
|
158
|
+
- lib/id3_tags/version.rb
|
159
|
+
- spec/assets/all_id3.mp3
|
160
|
+
- spec/assets/black_pixel.png
|
161
|
+
- spec/assets/no_id3.mp3
|
162
|
+
- spec/helpers/duplicate_file_helper.rb
|
163
|
+
- spec/lib/idempotency_spec.rb
|
164
|
+
- spec/lib/read_id3_tags_spec.rb
|
165
|
+
- spec/lib/write_id3_tags_spec.rb
|
166
|
+
homepage: https://github.com/topspin/id3_tags
|
167
|
+
licenses:
|
168
|
+
- MIT
|
169
|
+
post_install_message:
|
170
|
+
rdoc_options: []
|
171
|
+
require_paths:
|
172
|
+
- lib
|
173
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
174
|
+
none: false
|
175
|
+
requirements:
|
176
|
+
- - ! '>='
|
177
|
+
- !ruby/object:Gem::Version
|
178
|
+
version: '0'
|
179
|
+
segments:
|
180
|
+
- 0
|
181
|
+
hash: -1313956793775071095
|
182
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
183
|
+
none: false
|
184
|
+
requirements:
|
185
|
+
- - ! '>='
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0'
|
188
|
+
segments:
|
189
|
+
- 0
|
190
|
+
hash: -1313956793775071095
|
191
|
+
requirements: []
|
192
|
+
rubyforge_project:
|
193
|
+
rubygems_version: 1.8.23
|
194
|
+
signing_key:
|
195
|
+
specification_version: 3
|
196
|
+
summary: ! 'Id3Tags provides two methods: * read_tags_from, which reads an MP3 file
|
197
|
+
and returns a Hash of metadata * write_tags_to, which writes a Hash of metadata
|
198
|
+
into an MP3 file'
|
199
|
+
test_files:
|
200
|
+
- spec/assets/all_id3.mp3
|
201
|
+
- spec/assets/black_pixel.png
|
202
|
+
- spec/assets/no_id3.mp3
|
203
|
+
- spec/helpers/duplicate_file_helper.rb
|
204
|
+
- spec/lib/idempotency_spec.rb
|
205
|
+
- spec/lib/read_id3_tags_spec.rb
|
206
|
+
- spec/lib/write_id3_tags_spec.rb
|
207
|
+
has_rdoc:
|