id3_tags 0.0.1 → 0.0.2
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/bin/id3_tags +11 -0
- data/lib/id3_tags/m4a.rb +130 -0
- data/lib/id3_tags/mp3.rb +142 -0
- data/lib/id3_tags/version.rb +1 -1
- data/lib/id3_tags.rb +36 -147
- metadata +28 -44
- data/.gitignore +0 -16
- data/.rspec +0 -1
- data/Gemfile +0 -6
- data/HISTORY.md +0 -1
- data/Rakefile +0 -12
- data/TODO.md +0 -2
- data/doc/Id3Tags.html +0 -495
- data/doc/_index.html +0 -110
- data/doc/class_list.html +0 -53
- data/doc/css/common.css +0 -1
- data/doc/css/full_list.css +0 -57
- data/doc/css/style.css +0 -338
- data/doc/file.README.html +0 -102
- data/doc/file_list.html +0 -55
- data/doc/frames.html +0 -28
- data/doc/index.html +0 -102
- data/doc/js/app.js +0 -214
- data/doc/js/full_list.js +0 -178
- data/doc/js/jquery.js +0 -4
- data/doc/method_list.html +0 -64
- data/doc/top-level-namespace.html +0 -112
- data/id3_tags.gemspec +0 -30
- 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 +0 -11
- data/spec/lib/idempotency_spec.rb +0 -14
- data/spec/lib/read_id3_tags_spec.rb +0 -72
- data/spec/lib/write_id3_tags_spec.rb +0 -67
data/bin/id3_tags
ADDED
data/lib/id3_tags/m4a.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'taglib'
|
3
|
+
require 'active_support/core_ext/hash'
|
4
|
+
|
5
|
+
module Id3Tags
|
6
|
+
class M4A
|
7
|
+
def read_tags_from(file_path)
|
8
|
+
attrs = {}
|
9
|
+
TagLib::MP4::File.open(file_path) do |file|
|
10
|
+
tag_fields.each do |field, opts|
|
11
|
+
value = file.tag.item_list_map.fetch opts[:frame_id]
|
12
|
+
assign! attrs, field, value, opts[:type], opts[:default]
|
13
|
+
end unless file.tag.nil?
|
14
|
+
|
15
|
+
audio_properties_fields.each do |field, opts|
|
16
|
+
value = file.audio_properties.send opts[:method]
|
17
|
+
assign! attrs, field, value, :integer
|
18
|
+
end unless file.audio_properties.nil?
|
19
|
+
end
|
20
|
+
attrs.symbolize_keys
|
21
|
+
end
|
22
|
+
|
23
|
+
def write_tags_to(file_path, attrs = {})
|
24
|
+
attrs.symbolize_keys!
|
25
|
+
|
26
|
+
TagLib::MP4::File.open(file_path) do |file|
|
27
|
+
tag_fields.each do |field, opts|
|
28
|
+
file.tag.item_list_map.erase opts[:frame_id]
|
29
|
+
frame = new_frame_for attrs[field], opts[:frame_id], opts[:type]
|
30
|
+
file.tag.item_list_map.insert opts[:frame_id], frame if frame
|
31
|
+
end unless file.tag.nil?
|
32
|
+
|
33
|
+
file.save
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def fields
|
40
|
+
{
|
41
|
+
album_artist: {on: :tag, frame_id: 'aART', type: :string},
|
42
|
+
artist: {on: :tag, frame_id: '©ART', type: :string},
|
43
|
+
title: {on: :tag, frame_id: '©nam', type: :string},
|
44
|
+
album: {on: :tag, frame_id: '©alb', type: :string},
|
45
|
+
comment: {on: :tag, frame_id: '©cmt', type: :string},
|
46
|
+
genre: {on: :tag, frame_id: '©gen', type: :string},
|
47
|
+
grouping: {on: :tag, frame_id: '©grp', type: :string},
|
48
|
+
lyrics: {on: :tag, frame_id: '©lyr', type: :string},
|
49
|
+
composer: {on: :tag, frame_id: '©wrt', type: :string},
|
50
|
+
year: {on: :tag, frame_id: '©day', type: :string, default: 0},
|
51
|
+
disk: {on: :tag, frame_id: 'disk', type: :pair},
|
52
|
+
track: {on: :tag, frame_id: 'trkn', type: :pair},
|
53
|
+
bpm: {on: :tag, frame_id: 'tmpo', type: :integer},
|
54
|
+
compilation: {on: :tag, frame_id: 'cpil', type: :boolean},
|
55
|
+
cover_art: {on: :tag, frame_id: 'covr', type: :image},
|
56
|
+
bitrate: {on: :audio_properties, method: :bitrate},
|
57
|
+
channels: {on: :audio_properties, method: :channels},
|
58
|
+
length: {on: :audio_properties, method: :length},
|
59
|
+
samplerate: {on: :audio_properties, method: :sample_rate},
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
def assign!(attrs, field, value, type, default = nil)
|
64
|
+
case type
|
65
|
+
when :string
|
66
|
+
attrs[field] = value && value.to_string_list.first
|
67
|
+
if default
|
68
|
+
if attrs[field]
|
69
|
+
attrs[field] = attrs[field].to_i
|
70
|
+
else
|
71
|
+
attrs[field] = default
|
72
|
+
end
|
73
|
+
end
|
74
|
+
when :integer
|
75
|
+
attrs[field] = value && value.to_int
|
76
|
+
if attrs[field] == 0 # well... always? or just bpm?
|
77
|
+
attrs[field] = nil
|
78
|
+
end
|
79
|
+
when :boolean
|
80
|
+
attrs[field] = value && value.to_bool
|
81
|
+
when :pair
|
82
|
+
pair = value ? value.to_int_pair : [nil, nil]
|
83
|
+
attrs[field] = {number: pair[0], count: pair[1]}
|
84
|
+
when :image
|
85
|
+
if value
|
86
|
+
image = value.to_cover_art_list.first
|
87
|
+
data = image.data
|
88
|
+
mime_type = case image.format
|
89
|
+
when TagLib::MP4::CoverArt::JPEG then 'image/jpeg'
|
90
|
+
when TagLib::MP4::CoverArt::PNG then 'image/png'
|
91
|
+
end
|
92
|
+
else
|
93
|
+
data, mime_type = [nil, nil]
|
94
|
+
end
|
95
|
+
attrs[:cover_art] = {data: data, mime_type: mime_type}
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def tag_fields
|
100
|
+
fields.select{|k,v| v[:on] == :tag}
|
101
|
+
end
|
102
|
+
|
103
|
+
def audio_properties_fields
|
104
|
+
fields.select{|k,v| v[:on] == :audio_properties }
|
105
|
+
end
|
106
|
+
|
107
|
+
def new_frame_for(content, frame_id, type)
|
108
|
+
return if content.nil?
|
109
|
+
case type
|
110
|
+
when :string
|
111
|
+
TagLib::MP4::Item.from_string_list [content.to_s]
|
112
|
+
when :integer
|
113
|
+
TagLib::MP4::Item.from_int content.to_i
|
114
|
+
when :boolean
|
115
|
+
TagLib::MP4::Item.from_bool content
|
116
|
+
when :pair
|
117
|
+
return unless content.has_key? :number
|
118
|
+
TagLib::MP4::Item.from_int_pair content.values_at(:number, :count)
|
119
|
+
when :image
|
120
|
+
return unless content.has_key? :data
|
121
|
+
mime_type = case content[:mime_type]
|
122
|
+
when 'image/jpeg' then TagLib::MP4::CoverArt::JPEG
|
123
|
+
when 'image/png' then TagLib::MP4::CoverArt::PNG
|
124
|
+
end
|
125
|
+
cover_art = TagLib::MP4::CoverArt.new mime_type, content[:data]
|
126
|
+
TagLib::MP4::Item.from_cover_art_list [cover_art]
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
data/lib/id3_tags/mp3.rb
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'taglib'
|
2
|
+
require 'active_support/core_ext/hash'
|
3
|
+
|
4
|
+
module Id3Tags
|
5
|
+
class MPEG
|
6
|
+
def read_tags_from(file_path)
|
7
|
+
attrs = {}
|
8
|
+
TagLib::MPEG::File.open(file_path) do |file|
|
9
|
+
tag_fields.each do |field, opts|
|
10
|
+
value = file.tag.send opts[:method]
|
11
|
+
assign! attrs, field, value, opts[:type]
|
12
|
+
end unless file.tag.nil?
|
13
|
+
|
14
|
+
audio_properties_fields.each do |field, opts|
|
15
|
+
value = file.audio_properties.send opts[:method]
|
16
|
+
assign! attrs, field, value, :integer
|
17
|
+
end unless file.audio_properties.nil?
|
18
|
+
|
19
|
+
id3v2_tag_fields.each do |field, opts|
|
20
|
+
value = file.id3v2_tag.frame_list(opts[:frame_id]).first
|
21
|
+
value = value.to_string if value and opts[:type] != :image
|
22
|
+
assign! attrs, field, value, opts[:type]
|
23
|
+
end unless file.id3v2_tag.nil?
|
24
|
+
end
|
25
|
+
|
26
|
+
attrs.symbolize_keys
|
27
|
+
end
|
28
|
+
|
29
|
+
def write_tags_to(file_path, attrs = {})
|
30
|
+
attrs.symbolize_keys!
|
31
|
+
|
32
|
+
TagLib::MPEG::File.open(file_path) do |file|
|
33
|
+
tag_fields.each do |field, opts|
|
34
|
+
file.tag.send "#{opts[:method]}=", (attrs[field] || opts[:default])
|
35
|
+
end unless file.tag.nil?
|
36
|
+
|
37
|
+
id3v2_tag_fields.each do |field, opts|
|
38
|
+
file.id3v2_tag.remove_frames opts[:frame_id]
|
39
|
+
frame = new_frame_for attrs[field], opts[:frame_id], opts[:type]
|
40
|
+
file.id3v2_tag.add_frame frame if frame
|
41
|
+
end unless file.id3v2_tag.nil?
|
42
|
+
|
43
|
+
file.save
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def fields
|
50
|
+
{
|
51
|
+
title: {on: :tag, method: :title, type: :string},
|
52
|
+
album: {on: :tag, method: :album, type: :string},
|
53
|
+
artist: {on: :tag, method: :artist, type: :string},
|
54
|
+
comment: {on: :tag, method: :comment, type: :string},
|
55
|
+
genre: {on: :tag, method: :genre, type: :string},
|
56
|
+
year: {on: :tag, method: :year, type: :integer, default: 0},
|
57
|
+
bpm: {on: :id3v2_tag, frame_id: 'TBPM', type: :integer},
|
58
|
+
lyrics: {on: :id3v2_tag, frame_id: 'USLT', type: :text},
|
59
|
+
composer: {on: :id3v2_tag, frame_id: 'TCOM', type: :string},
|
60
|
+
grouping: {on: :id3v2_tag, frame_id: 'TIT1', type: :string},
|
61
|
+
album_artist: {on: :id3v2_tag, frame_id: 'TPE2', type: :string},
|
62
|
+
compilation: {on: :id3v2_tag, frame_id: 'TCMP', type: :boolean},
|
63
|
+
track: {on: :id3v2_tag, frame_id: 'TRCK', type: :pair},
|
64
|
+
disk: {on: :id3v2_tag, frame_id: 'TPOS', type: :pair},
|
65
|
+
cover_art: {on: :id3v2_tag, frame_id: 'APIC', type: :image},
|
66
|
+
bitrate: {on: :audio_properties, method: :bitrate},
|
67
|
+
channels: {on: :audio_properties, method: :channels},
|
68
|
+
length: {on: :audio_properties, method: :length},
|
69
|
+
samplerate: {on: :audio_properties, method: :sample_rate},
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
def tag_fields
|
74
|
+
fields.select{|k,v| v[:on] == :tag}
|
75
|
+
end
|
76
|
+
|
77
|
+
def audio_properties_fields
|
78
|
+
fields.select{|k,v| v[:on] == :audio_properties }
|
79
|
+
end
|
80
|
+
|
81
|
+
def id3v2_tag_fields
|
82
|
+
fields.select{|k,v| v[:on] == :id3v2_tag }
|
83
|
+
end
|
84
|
+
|
85
|
+
def assign!(attrs, field, value, type)
|
86
|
+
case type
|
87
|
+
when :string, :text
|
88
|
+
attrs[field] = value && value.to_s
|
89
|
+
when :integer
|
90
|
+
attrs[field] = value && value.to_i
|
91
|
+
when :boolean
|
92
|
+
attrs[field] = value.present? && value.eql?('1')
|
93
|
+
when :pair
|
94
|
+
pair = value ? value.split('/').map(&:to_i) : [nil, nil]
|
95
|
+
attrs[field] = {number: pair[0], count: pair[1]}
|
96
|
+
when :image
|
97
|
+
pair = [value && value.mime_type, value && value.picture].map(&:presence)
|
98
|
+
attrs[field] = {mime_type: pair[0], data: pair[1]}
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def new_frame_for(content, frame_id, type)
|
103
|
+
return if content.nil?
|
104
|
+
case type
|
105
|
+
when :string, :integer
|
106
|
+
frame = new_string_frame(frame_id)
|
107
|
+
frame.text = content.to_s
|
108
|
+
when :text
|
109
|
+
frame = new_text_frame(frame_id)
|
110
|
+
frame.text = content.to_s
|
111
|
+
when :boolean
|
112
|
+
return unless content.eql?(true)
|
113
|
+
frame = new_string_frame(frame_id)
|
114
|
+
frame.text = '1'
|
115
|
+
when :pair
|
116
|
+
return unless content.has_key? :number
|
117
|
+
frame = new_string_frame(frame_id)
|
118
|
+
frame.text = content.values_at(:number, :count).compact.join '/'
|
119
|
+
when :image
|
120
|
+
return unless content.has_key? :data
|
121
|
+
frame = new_image_frame(frame_id)
|
122
|
+
frame.description = 'Cover'
|
123
|
+
frame.type = TagLib::ID3v2::AttachedPictureFrame::FrontCover
|
124
|
+
frame.mime_type = content[:mime_type]
|
125
|
+
frame.picture = content[:data]
|
126
|
+
end
|
127
|
+
frame
|
128
|
+
end
|
129
|
+
|
130
|
+
def new_string_frame(frame_id)
|
131
|
+
TagLib::ID3v2::TextIdentificationFrame.new frame_id, TagLib::String::UTF8
|
132
|
+
end
|
133
|
+
|
134
|
+
def new_text_frame(frame_id)
|
135
|
+
TagLib::ID3v2::UnsynchronizedLyricsFrame.new frame_id
|
136
|
+
end
|
137
|
+
|
138
|
+
def new_image_frame(frame_id)
|
139
|
+
TagLib::ID3v2::AttachedPictureFrame.new frame_id
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
data/lib/id3_tags/version.rb
CHANGED
data/lib/id3_tags.rb
CHANGED
@@ -1,51 +1,37 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
1
|
+
require 'mimemagic'
|
2
|
+
require 'id3_tags/mp3'
|
3
|
+
require 'id3_tags/m4a'
|
3
4
|
|
4
|
-
# Provides two methods to read and write ID3 metadata from an MP3 file
|
5
|
+
# Provides two methods to read and write ID3 metadata from an MP3 or M4A file
|
5
6
|
module Id3Tags
|
6
7
|
|
7
8
|
# Returns a Hash of ID3 attributes stored in the file located at +file_path+.
|
8
9
|
#
|
9
|
-
# @param [String] file_path Local path to an MP3 file
|
10
|
+
# @param [String] file_path Local path to an MP3 or M4A file
|
10
11
|
# @return [Hash] the ID3 attributes stored in the file
|
11
12
|
#
|
12
13
|
# @example Read tags from an MP3 full of metadata
|
13
14
|
# Id3Tags.read_tags_from("all_id3.mp3")
|
14
15
|
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
16
|
+
# # => {title: "Sample track", album: "Sample album", artist: Sample
|
17
|
+
# artist", :comment=>"Sample comments", genre: "Sample Genre",
|
18
|
+
# year: 1979, bitrate: 128, channels: 2, length: 38, samplerate:
|
19
|
+
# 44100, bpm: 110, lyrics: "Sample lyrics line 1\rand line 2",
|
20
|
+
# composer: "Sample composer", grouping: "Sample group",
|
21
|
+
# album_artist: "Sample album artist", compilation: true, track:
|
22
|
+
# {number: 3, count: 12}, disk: {number: 1, count: 2}, cover_art:
|
23
|
+
# {mime_type: "image/png", data: "\x89PNG\r\n\x1A[...]"}}
|
23
24
|
def self.read_tags_from(file_path)
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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?
|
25
|
+
case mime_type_of(file_path)
|
26
|
+
when 'audio/mpeg' then MPEG.new.read_tags_from(file_path)
|
27
|
+
when 'audio/mp4' then M4A.new.read_tags_from(file_path)
|
28
|
+
else {}
|
41
29
|
end
|
42
|
-
|
43
|
-
attrs.symbolize_keys
|
44
30
|
end
|
45
31
|
|
46
32
|
# Stores the +attrs+ Hash of ID3 attributes into the file at +file_path+.
|
47
33
|
#
|
48
|
-
# @param [String] file_path Local path to an MP3 file
|
34
|
+
# @param [String] file_path Local path to an MP3 or M4A file
|
49
35
|
# @param [Hash] attrs the ID3 attributes stored in the file
|
50
36
|
# @return [Boolean] true (the file gets changed)
|
51
37
|
#
|
@@ -59,124 +45,27 @@ module Id3Tags
|
|
59
45
|
# track: {number: 3, count: 12}, disk: {number: 1, count: 2},
|
60
46
|
# cover_art: {mime_type: "image/png", data: "\x89PNG\r\n\x1A[...]"}}
|
61
47
|
#
|
62
|
-
#
|
48
|
+
# # => true
|
63
49
|
def self.write_tags_to(file_path, attrs = {})
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
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
|
50
|
+
case mime_type_of(file_path)
|
51
|
+
when 'audio/mpeg' then MPEG.new.write_tags_to(file_path, attrs)
|
52
|
+
when 'audio/mp4' then M4A.new.write_tags_to(file_path, attrs)
|
53
|
+
else false
|
78
54
|
end
|
79
55
|
end
|
80
56
|
|
81
|
-
#
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
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
|
57
|
+
# Returns the MIME type of the file located at +file_path+.
|
58
|
+
#
|
59
|
+
# @param [String] file_path Local path to a file
|
60
|
+
# @return [String] the MIME type of the file
|
61
|
+
#
|
62
|
+
# @example Return the MIME type of an M4A file with a wrong '.mp3' extension
|
63
|
+
# Id3Tags.mime_type_of("this_is_an_m4a.mp3")
|
64
|
+
#
|
65
|
+
# # => "audio/mpeg"
|
66
|
+
def self.mime_type_of(file_path)
|
67
|
+
mime_type = MimeMagic.by_magic File.open(file_path)
|
68
|
+
mime_type ||= MimeMagic.by_path file_path
|
69
|
+
mime_type &&= mime_type.type
|
181
70
|
end
|
182
71
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: id3_tags
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-06-
|
12
|
+
date: 2013-06-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: taglib-ruby
|
@@ -43,6 +43,22 @@ dependencies:
|
|
43
43
|
- - ! '>='
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: mimemagic
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
46
62
|
- !ruby/object:Gem::Dependency
|
47
63
|
name: bundler
|
48
64
|
requirement: !ruby/object:Gem::Requirement
|
@@ -126,43 +142,18 @@ dependencies:
|
|
126
142
|
description: Read and write ID3 metadata from/to MP3 files
|
127
143
|
email:
|
128
144
|
- claudio@topspinmedia.com
|
129
|
-
executables:
|
145
|
+
executables:
|
146
|
+
- id3_tags
|
130
147
|
extensions: []
|
131
148
|
extra_rdoc_files: []
|
132
149
|
files:
|
133
|
-
-
|
134
|
-
- .
|
135
|
-
-
|
136
|
-
-
|
150
|
+
- bin/id3_tags
|
151
|
+
- lib/id3_tags/m4a.rb
|
152
|
+
- lib/id3_tags/mp3.rb
|
153
|
+
- lib/id3_tags/version.rb
|
154
|
+
- lib/id3_tags.rb
|
137
155
|
- MIT-LICENSE
|
138
156
|
- 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
157
|
homepage: https://github.com/topspin/id3_tags
|
167
158
|
licenses:
|
168
159
|
- MIT
|
@@ -178,7 +169,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
178
169
|
version: '0'
|
179
170
|
segments:
|
180
171
|
- 0
|
181
|
-
hash: -
|
172
|
+
hash: -2869380124724698312
|
182
173
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
183
174
|
none: false
|
184
175
|
requirements:
|
@@ -187,7 +178,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
187
178
|
version: '0'
|
188
179
|
segments:
|
189
180
|
- 0
|
190
|
-
hash: -
|
181
|
+
hash: -2869380124724698312
|
191
182
|
requirements: []
|
192
183
|
rubyforge_project:
|
193
184
|
rubygems_version: 1.8.23
|
@@ -196,12 +187,5 @@ specification_version: 3
|
|
196
187
|
summary: ! 'Id3Tags provides two methods: * read_tags_from, which reads an MP3 file
|
197
188
|
and returns a Hash of metadata * write_tags_to, which writes a Hash of metadata
|
198
189
|
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
|
190
|
+
test_files: []
|
207
191
|
has_rdoc:
|
data/.gitignore
DELETED
data/.rspec
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
--color
|
data/Gemfile
DELETED
data/HISTORY.md
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
v0.0.1 - 2013/06/13 Implements `read_tags_from` and `write_tags_to`
|
data/Rakefile
DELETED
data/TODO.md
DELETED