id3 1.0.0.pre5 → 1.0.0.pre6
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 +19 -0
- data/Rakefile +2 -0
- data/examples/id3_statistics_with_Audiofile.rb +115 -0
- data/examples/mp3/example_mp3_file_with_id3v2_2_0.mp3 +0 -0
- data/examples/mp3/rheeeeet.mp3 +0 -0
- data/examples/old/example2.rb +134 -0
- data/examples/old/examples.rb +165 -0
- data/examples/old/id3statistics.rb +145 -0
- data/examples/read_remote_id3v2_tag.rb +74 -0
- data/id3.gemspec +33 -0
- data/lib/id3.rb +1 -0
- data/lib/id3/constants.rb +1 -1
- data/lib/id3/version.rb +3 -0
- metadata +48 -36
data/.gitignore
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
|
2
|
+
require 'awesome_print'
|
3
|
+
|
4
|
+
require 'id3'
|
5
|
+
|
6
|
+
|
7
|
+
require '../lib/helpers/recursive_helper'
|
8
|
+
|
9
|
+
|
10
|
+
# ------------------------------------------------------------------------------
|
11
|
+
def each_song(filename)
|
12
|
+
filename.chomp!
|
13
|
+
@mp3fileN += 1
|
14
|
+
|
15
|
+
# puts "Filename: #{filename}"
|
16
|
+
|
17
|
+
if File.size(filename) == 0
|
18
|
+
@empty_fileN += 1
|
19
|
+
puts "EMPTY MP3-File: #{filename}" # better to know this, hum?
|
20
|
+
return
|
21
|
+
end
|
22
|
+
|
23
|
+
mp3 = AudioFile.new(filename) # CAN WE CALL THIS WITH A BLOCK??
|
24
|
+
if mp3.id3_versions.empty?
|
25
|
+
@no_id3_tagN += 1
|
26
|
+
puts "NO ID3 TAGS: #{filename}" # better to know this, hum?
|
27
|
+
return
|
28
|
+
else
|
29
|
+
mp3.id3_versions.each do |v|
|
30
|
+
# count how often we saw a certain ID3 tag version
|
31
|
+
@id3_versionNH[v] += 1
|
32
|
+
|
33
|
+
if mp3.has_id3v2tag?
|
34
|
+
# count how often we saw a certain ID3v2 tag size
|
35
|
+
@id3v2_tag_sizesH[v][mp3.tagID3v2.raw.size] ||= 0
|
36
|
+
@id3v2_tag_sizesH[v][mp3.tagID3v2.raw.size] += 1
|
37
|
+
|
38
|
+
# count how often we saw a certain ID3v2 tag
|
39
|
+
mp3.tagID3v2.keys.each do |tag|
|
40
|
+
@id3v2_fields_usedH[v][tag] ||= 0
|
41
|
+
@id3v2_fields_usedH[v][tag] += 1
|
42
|
+
end
|
43
|
+
else
|
44
|
+
@only_id3v1_tagN += 1 # if a file only has a ID3v1 tag, we also need a warning message
|
45
|
+
puts "ONLY ID3v1 TAG: #{filename}" # better to know this, hum?
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
# ------------------------------------------------------------------------------
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
mp3_library_dir = File.join( ENV['HOME'] , 'Music/iTunes/iTunes Music') # e.g. on a Mac
|
55
|
+
|
56
|
+
@dirN = 0
|
57
|
+
@fileN = 0
|
58
|
+
@mp3fileN = 0
|
59
|
+
|
60
|
+
@empty_fileN = 0
|
61
|
+
@no_id3_tagN = 0
|
62
|
+
@only_id3v1_tagN = 0
|
63
|
+
|
64
|
+
@id3v2_fields_usedH = {}
|
65
|
+
@id3v2_tag_sizesH = {}
|
66
|
+
@id3_versionNH = {}
|
67
|
+
ID3::VERSIONS.each do |v|
|
68
|
+
@id3v2_fields_usedH[v] = {}
|
69
|
+
@id3v2_tag_sizesH[v] = {}
|
70
|
+
@id3_versionNH[v] = 0
|
71
|
+
end
|
72
|
+
|
73
|
+
# gather statistics on the ID3 tags used in your MP3 library:
|
74
|
+
recursive_dir_descend( mp3_library_dir , /.*.[mM][pP]3$/ , 'each_song(filename)'); 1
|
75
|
+
|
76
|
+
|
77
|
+
print "
|
78
|
+
Files checked: #{@fileN}
|
79
|
+
Dirs checked: #{@dirN}
|
80
|
+
|
81
|
+
MP3 Files found: #{@mp3fileN}
|
82
|
+
|
83
|
+
Empty MP3 Files: #{@empty_fileN}
|
84
|
+
|
85
|
+
NO ID3 Tag at all: #{@no_id3_tagN}
|
86
|
+
|
87
|
+
ONLY ID3v2 Tag: #{@only_id3v1_tagN}
|
88
|
+
|
89
|
+
"
|
90
|
+
|
91
|
+
puts '--------------------'
|
92
|
+
ap @id3v2_fields_usedH ; 1
|
93
|
+
puts '--------------------'
|
94
|
+
ap @id3v2_tag_sizesH ;1
|
95
|
+
puts '--------------------'
|
96
|
+
ap @id3_versionNH ;1
|
97
|
+
puts '--------------------'
|
98
|
+
|
99
|
+
print "
|
100
|
+
Files checked: #{@fileN}
|
101
|
+
Dirs checked: #{@dirN}
|
102
|
+
|
103
|
+
MP3 Files found: #{@mp3fileN}
|
104
|
+
|
105
|
+
Empty MP3 Files: #{@empty_fileN}
|
106
|
+
|
107
|
+
NO ID3 Tag at all: #{@no_id3_tagN}
|
108
|
+
|
109
|
+
ONLY ID3v2 Tag: #{@only_id3v1_tagN}
|
110
|
+
|
111
|
+
"
|
112
|
+
|
113
|
+
puts "\n\ndone."
|
114
|
+
|
115
|
+
|
Binary file
|
Binary file
|
@@ -0,0 +1,134 @@
|
|
1
|
+
|
2
|
+
require 'id3'
|
3
|
+
|
4
|
+
tag1 = ID3::Tag1.new
|
5
|
+
tag1.read('mp3/d.mp3')
|
6
|
+
|
7
|
+
tag2 = ID3::Tag1.new
|
8
|
+
tag2.read('mp3/a.mp3')
|
9
|
+
|
10
|
+
raw = tag1.dump
|
11
|
+
raw.hexdump
|
12
|
+
tag1.raw.hexdump
|
13
|
+
|
14
|
+
t = ID3::Tag1.new
|
15
|
+
v,h = t.parse!(raw)
|
16
|
+
|
17
|
+
|
18
|
+
raw = tag2.dump
|
19
|
+
raw.hexdump
|
20
|
+
v,h = t.parse!(raw)
|
21
|
+
|
22
|
+
|
23
|
+
t['BLA'] = "blubb"
|
24
|
+
|
25
|
+
# --------------------------------------------------------------------------------
|
26
|
+
|
27
|
+
require 'id3'
|
28
|
+
|
29
|
+
t = ID3::Tag2.new
|
30
|
+
t.read("mp3/d.mp3")
|
31
|
+
t["ARTIST"]
|
32
|
+
|
33
|
+
t["ARTIST"].dump.hexdump
|
34
|
+
|
35
|
+
t.delete('PICTURE')
|
36
|
+
t.dump.hexdump
|
37
|
+
|
38
|
+
# --------------------------------------------------------------------------------
|
39
|
+
|
40
|
+
require 'id3'
|
41
|
+
|
42
|
+
a = ID3::AudioFile.new("mp3/a.mp3")
|
43
|
+
t1 = a.write
|
44
|
+
a1 = a.writeAudio
|
45
|
+
|
46
|
+
aa = ID3::AudioFile.new( t1 )
|
47
|
+
t2 = aa.write
|
48
|
+
a2 = aa.writeAudio
|
49
|
+
|
50
|
+
aaa = ID3::AudioFile.new( t2 )
|
51
|
+
t3 = aaa.write
|
52
|
+
a3 = aaa.writeAudio
|
53
|
+
|
54
|
+
a.audioLength
|
55
|
+
aa.audioLength
|
56
|
+
aaa.audioLength
|
57
|
+
|
58
|
+
` ls -l t1 t2 t3`
|
59
|
+
|
60
|
+
# to create a test file
|
61
|
+
|
62
|
+
File.open("mp3/test.mp3", "w+") { |f|
|
63
|
+
256.times { |i|
|
64
|
+
f.putc i
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
# --------------------------------------------------------------------------------
|
69
|
+
|
70
|
+
|
71
|
+
require 'id3'
|
72
|
+
|
73
|
+
a = ID3::AudioFile.new("mp3/a.mp3")
|
74
|
+
b = ID3::AudioFile.new("mp3/b.mp3")
|
75
|
+
c = ID3::AudioFile.new("mp3/c.mp3")
|
76
|
+
d = ID3::AudioFile.new("mp3/d.mp3")
|
77
|
+
e = ID3::AudioFile.new("mp3/reeeee.mp3")
|
78
|
+
a = ID3::AudioFile.new("mp3/King_Crimson_-_Three_of_a_Perfect_Pair_-_06_-_Industry.mp3")
|
79
|
+
|
80
|
+
d.tagID3v2["TMEDIATYPE"].flags
|
81
|
+
|
82
|
+
d.tagID3v2.version
|
83
|
+
d.tagID3v2["ARTIST"].rawflags
|
84
|
+
d.tagID3v2["ARTIST"].flags
|
85
|
+
|
86
|
+
d.tagID3v2["ARTIST"].raw
|
87
|
+
d.tagID3v2["ARTIST"].rawheader
|
88
|
+
d.tagID3v2["ARTIST"].rawdata
|
89
|
+
|
90
|
+
|
91
|
+
t = ID3::Tag2.new
|
92
|
+
t.read("mp3/b.mp3")
|
93
|
+
|
94
|
+
t["COMMENT"]
|
95
|
+
t["COMMENT"].order
|
96
|
+
|
97
|
+
t["COMMENT"]["bla"] =3
|
98
|
+
|
99
|
+
|
100
|
+
|
101
|
+
t['COMMENT'].rawdata.hexdump
|
102
|
+
|
103
|
+
|
104
|
+
|
105
|
+
t2["SONGLEN"].rawdata.hexdump
|
106
|
+
t2["SONGLEN"].dump.hexdump
|
107
|
+
|
108
|
+
|
109
|
+
# to check which symbols don't have a matching pack/unpack pattern:
|
110
|
+
|
111
|
+
(ID3::Framename2symbol["2.2.0"].values +
|
112
|
+
ID3::Framename2symbol["2.3.0"].values +
|
113
|
+
ID3::Framename2symbol["2.4.0"].values).uniq.each { |symbol|
|
114
|
+
print "SYMBOL: #{symbol} not defined!\n" if ! ID3::FrameName2FrameType[symbol]
|
115
|
+
}
|
116
|
+
|
117
|
+
|
118
|
+
|
119
|
+
ID3::FrameName2FrameType["ARTIST"]
|
120
|
+
ID3::FrameName2FrameType
|
121
|
+
|
122
|
+
|
123
|
+
t2["ARTIST"].raw
|
124
|
+
|
125
|
+
t2["ARTIST"].rawdata
|
126
|
+
|
127
|
+
|
128
|
+
|
129
|
+
|
130
|
+
t1 = ID3::Tag2.new
|
131
|
+
t1.read("mp3/b.mp3")
|
132
|
+
t1["ARTIST"]
|
133
|
+
|
134
|
+
|
@@ -0,0 +1,165 @@
|
|
1
|
+
|
2
|
+
# ------------------------------------------------------------------------------
|
3
|
+
# SOME EXAMPLES on how the library is intended to be used
|
4
|
+
# ------------------------------------------------------------------------------
|
5
|
+
|
6
|
+
# EXAMPLE of stripping extra v1-tag if v2-tag is present:
|
7
|
+
|
8
|
+
file = "bla.mp3"
|
9
|
+
if ID3::has_id3_tag?( file )
|
10
|
+
myfile = AudioFile.open( file ) # do we need a new here?
|
11
|
+
|
12
|
+
# if a file has both tags (v1 and v2), we delete the v1 tag:
|
13
|
+
if (myfile.has_id3v1_tag?) && (myfile.has_id3v2_tag?)
|
14
|
+
myfile.id3v1tag = nil
|
15
|
+
myfile.write # we only write if we modified it..
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# NOTE: may use id3v1tag.clear or id3v1tag = {} instead
|
20
|
+
|
21
|
+
# ------------------------------------------------------------------------------
|
22
|
+
|
23
|
+
# EXAMPLE of stripping attached pictures from id3v2-tags if present,
|
24
|
+
# and re-setting the play counter to 0
|
25
|
+
# and setting the comment to something silly
|
26
|
+
|
27
|
+
file = "bla.mp3"
|
28
|
+
if ID3::has_id3v2_tag?( file )
|
29
|
+
myfile = AudioFile.open( file ) # do we need a new here?
|
30
|
+
# if (myfile.id3v2tag.member?(PICTURE)) # if there is a picture in the tag..
|
31
|
+
myfile.id3v2tag.delete(PICTURE) # deletes the unwanted picture..
|
32
|
+
# end
|
33
|
+
myfile.id3v2tag["PLAYCOUNTER"] = 0 # reset the play counter to 0
|
34
|
+
myfile.id3v2tag["COMMENT"] = "Tilo's MP3 collection" # set the comment
|
35
|
+
|
36
|
+
myfile.id3v2tag.options["PADDINGSIZE"] = 0 # shrink the tag!
|
37
|
+
myfile.id3v2tag.options["APPENDTAG"] = false # shrink the tag!
|
38
|
+
myfile.id3v2tag.options["FOOTER"] = false # shrink the tag!
|
39
|
+
myfile.id3v2tag.options["EXT_HEADER"] = false # shrink the tag!
|
40
|
+
|
41
|
+
myfile.write # writes to the same filename, overwriting the old file
|
42
|
+
myfile.write("new.mp3") # creates new file
|
43
|
+
myfile.close
|
44
|
+
end
|
45
|
+
|
46
|
+
# ------------------------------------------------------------------------------
|
47
|
+
|
48
|
+
# CODE FRAGMENT from initialization of AudioFile
|
49
|
+
|
50
|
+
# when we open a file and create a new ID3-tag, we should do this internally:
|
51
|
+
|
52
|
+
v1 = ID3::has_id3v1_tag?( file )
|
53
|
+
v2 = ID3::has_id3v2_tag?( file ) # but may not be a version we know
|
54
|
+
# about...
|
55
|
+
|
56
|
+
if (v2) # if version is not nil
|
57
|
+
id3v2tag = ID3v2tag.new( v2 ) # only create tag if one in file
|
58
|
+
end
|
59
|
+
|
60
|
+
if (v1)
|
61
|
+
id3v1tag = ID3v1tag.new( v1 ) # only create tag if one in file
|
62
|
+
end
|
63
|
+
|
64
|
+
# or we do it the same way as in the old library:
|
65
|
+
|
66
|
+
v1 = ID3::has_id3v1_tag?( file )
|
67
|
+
v2 = ID3::has_id3v2_tag?( file )
|
68
|
+
|
69
|
+
id3v2tag = ID3v2tag.new( v2 )
|
70
|
+
id3v2tag.read_v2(file)
|
71
|
+
|
72
|
+
|
73
|
+
# similarly, when creating a new frame, we need to read it first,
|
74
|
+
# before we can create the correct instance with the correct singleton
|
75
|
+
# methods...
|
76
|
+
|
77
|
+
frame = Frame.new # should create a new frame of the correct type..
|
78
|
+
|
79
|
+
# ------------------------------------------------------------------------------
|
80
|
+
|
81
|
+
|
82
|
+
|
83
|
+
|
84
|
+
|
85
|
+
------------------------------------------------------------------------------
|
86
|
+
|
87
|
+
# EXAMPLE tagging an existing MP3 track..
|
88
|
+
|
89
|
+
file = "/tmp/rheeeeet.mp3" # ./examples/mp3/rheeeeet.mp3
|
90
|
+
|
91
|
+
if ! ID3.hasID3v2tag?(file) # if there is no v2 tag
|
92
|
+
|
93
|
+
myfile = AudioFile.new( file ) # do we need a new here?
|
94
|
+
|
95
|
+
newtag = ID3::Tag2.new # create a new,empty v2 tag
|
96
|
+
newtag.version = '2.3.0'
|
97
|
+
newtag["TITLE"] = "Reeeeet!"
|
98
|
+
newtag["ARTIST"] = "Dan Mosedale"
|
99
|
+
newtag["LYRICIST"] = "Dan Mosedale"
|
100
|
+
newtag["COMPOSER"] = "Dan Mosedale"
|
101
|
+
newtag["LANGUAGE"] = "Monkey" # should raise an error, because there is no
|
102
|
+
# ISO language code for "Monkey"
|
103
|
+
|
104
|
+
newtag["BAND"] = "Mozilla and the ButtMonkeys"
|
105
|
+
newtag["TRACKNUM"] = '1' # will be converted to "1"
|
106
|
+
newtag["DATE"] = "2000/05/02" # will be converted to correct date format
|
107
|
+
|
108
|
+
newtag["COMMENT"] = "The sound which monkeys make when they are flying out of someones butt.. Which is refering to the estimated release date of Netscape 6. See: https://wiki.mozilla.org/SeaMonkey:Name_And_Version"
|
109
|
+
|
110
|
+
newtag.options["PADDINGSIZE"] = 0
|
111
|
+
|
112
|
+
myfile.tagID3v2 = newtag # assoziate the new tag with the AudioFile..
|
113
|
+
# NOTE: we should CHECK when assigning a tag,
|
114
|
+
# that the version number matches!
|
115
|
+
|
116
|
+
myfile.write # if we overwrite, we should save the old tag in "filename.oldtag"
|
117
|
+
myfile.close
|
118
|
+
end
|
119
|
+
------------------------------------------------------------------------------
|
120
|
+
|
121
|
+
# EXAMPLE to convert a file from older id3v2.x tags to id3v2.3 tags
|
122
|
+
|
123
|
+
file = "bla.mp3"
|
124
|
+
if ID3::has_id3v2_tag?( file )
|
125
|
+
myfile = AudioFile.open( file ) # do we need a new here?
|
126
|
+
|
127
|
+
if (myfile.id3v2tag.version < "2.3.0")
|
128
|
+
|
129
|
+
|
130
|
+
newtag = ID3v2tag("2.3.0")
|
131
|
+
|
132
|
+
# newtag = ID3v2tag.new # create new empty tag
|
133
|
+
# newtag.version = "2.3.0" # of specific version
|
134
|
+
|
135
|
+
myfile.id3v2tag.each { |key, value|
|
136
|
+
newtag[key] = value
|
137
|
+
}
|
138
|
+
myfile.id3v2tag = newtag
|
139
|
+
|
140
|
+
myfile.id3v2tag.options["PADDINGSIZE"] = 0 # shrink the tag!
|
141
|
+
|
142
|
+
myfile.write # writes to the same filename, overwriting the old file
|
143
|
+
myfile.write("new.mp3") # creates new file
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
myfile.close
|
148
|
+
end
|
149
|
+
|
150
|
+
------------------------------------------------------------------------------
|
151
|
+
|
152
|
+
# EXAMPLE to check if two tags are equivalent.. e.g. if they contain the
|
153
|
+
# same fields with the same values..
|
154
|
+
|
155
|
+
ID3::tags_equivalent(other)
|
156
|
+
|
157
|
+
# we also need to check if the number of keys is the same in each hash
|
158
|
+
|
159
|
+
equivalent = true
|
160
|
+
self.each { |key,value|
|
161
|
+
equivalent = false if self[key] != other[key]
|
162
|
+
}
|
163
|
+
return equivalent
|
164
|
+
|
165
|
+
------------------------------------------------------------------------------
|
@@ -0,0 +1,145 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
# this script collects statistical output about ID3 collection
|
4
|
+
#
|
5
|
+
|
6
|
+
require "id3"
|
7
|
+
|
8
|
+
|
9
|
+
# ------------------------------------------------------------------------------
|
10
|
+
# recursiveDirectoryDescend
|
11
|
+
# do action for files matching regexp
|
12
|
+
#
|
13
|
+
# could be extended to array of (regexp,action) pairs
|
14
|
+
#
|
15
|
+
def recursiveDirectoryDescend(dir,regexp,action)
|
16
|
+
# print "dir : #{dir}\n"
|
17
|
+
|
18
|
+
olddir = Dir.pwd
|
19
|
+
dirp = Dir.open(dir)
|
20
|
+
Dir.chdir(dir)
|
21
|
+
pwd = Dir.pwd
|
22
|
+
@@dirN += 1
|
23
|
+
|
24
|
+
for file in dirp
|
25
|
+
file.chomp
|
26
|
+
next if file =~ /^\.\.?$/
|
27
|
+
|
28
|
+
fullname = "#{pwd}/#{file}"
|
29
|
+
|
30
|
+
if File::directory?(fullname)
|
31
|
+
recursiveDirectoryDescend(fullname,regexp,action)
|
32
|
+
else
|
33
|
+
@@fileN += 1
|
34
|
+
if file =~ regexp
|
35
|
+
# evaluate action
|
36
|
+
eval action
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
Dir.chdir(olddir)
|
41
|
+
end
|
42
|
+
# ------------------------------------------------------------------------------
|
43
|
+
|
44
|
+
def eachSong(filename)
|
45
|
+
filename.chomp!
|
46
|
+
print "MP3-FILE: #{filename}"
|
47
|
+
@@mp3fileN += 1
|
48
|
+
|
49
|
+
if (File.size(filename) == 0)
|
50
|
+
puts " -- empty file\n"
|
51
|
+
return
|
52
|
+
end
|
53
|
+
|
54
|
+
v = 0
|
55
|
+
tagN = 0
|
56
|
+
|
57
|
+
v = ID3::hasID3v1tag?(filename)
|
58
|
+
if v
|
59
|
+
print " -- found ID3-tag version #{v}"
|
60
|
+
@@id3versionN[v] += 1
|
61
|
+
tagN += 1
|
62
|
+
end
|
63
|
+
|
64
|
+
v = ID3::hasID3v2tag?(filename)
|
65
|
+
if v
|
66
|
+
print " -- found ID3-tag version #{v}"
|
67
|
+
@@id3versionN[v] += 1
|
68
|
+
tagN += 1
|
69
|
+
|
70
|
+
tag2= ID3::Tag2.new
|
71
|
+
tag2.read(filename)
|
72
|
+
|
73
|
+
size = tag2.raw.size
|
74
|
+
@@sizeSum += size
|
75
|
+
@@sizeMax = size if size > @@sizeMax
|
76
|
+
printf "\ntag-size: %d , tag-keys: %s\n", size, tag2.keys.join(',')
|
77
|
+
|
78
|
+
|
79
|
+
tag2.keys.each { |field|
|
80
|
+
@@fieldsUsedN[tag2.version][field] += 1
|
81
|
+
}
|
82
|
+
end
|
83
|
+
if tagN == 0
|
84
|
+
print " -- no ID3-tag"
|
85
|
+
end
|
86
|
+
@@tagsPerFileN[tagN] += 1
|
87
|
+
puts "\n"
|
88
|
+
end
|
89
|
+
# ------------------------------------------------------------------------------
|
90
|
+
|
91
|
+
|
92
|
+
@@fileN = 0
|
93
|
+
@@mp3fileN = 0
|
94
|
+
@@dirN = 0
|
95
|
+
@@id3versionN = Hash.new(0)
|
96
|
+
|
97
|
+
@@fieldsUsedN = {}
|
98
|
+
ID3::VERSIONS.each do |v|
|
99
|
+
@@fieldsUsedN[v] ||= Hash.new(0)
|
100
|
+
end
|
101
|
+
|
102
|
+
@@sizeMax = 0
|
103
|
+
@@sizeSum = 0
|
104
|
+
|
105
|
+
|
106
|
+
@@tagsPerFileN= Array.new(3,0)
|
107
|
+
|
108
|
+
dir = ARGV[0]
|
109
|
+
|
110
|
+
recursiveDirectoryDescend(dir, /.*\.[mM][pP]3/, %q{ eachSong(fullname) } )
|
111
|
+
|
112
|
+
|
113
|
+
print "
|
114
|
+
|
115
|
+
Files checked : #{@@fileN}
|
116
|
+
Directories checked: #{@@dirN}
|
117
|
+
|
118
|
+
MP3 Files found : #{@@mp3fileN}
|
119
|
+
"
|
120
|
+
|
121
|
+
version2tagN = 0
|
122
|
+
|
123
|
+
@@id3versionN.keys.each { |v|
|
124
|
+
printf "\nnumber of ID3 tags v#{v} : #{@@id3versionN[v]}\n"
|
125
|
+
version2tagN += 1 if v =~ /^2\./
|
126
|
+
}
|
127
|
+
|
128
|
+
puts "\n"
|
129
|
+
|
130
|
+
@@tagsPerFileN.each_index{ |x|
|
131
|
+
printf "\nFiles tagged #{x}-times : #{@@tagsPerFileN[x]}\n"
|
132
|
+
}
|
133
|
+
|
134
|
+
ID3::SUPPORTED_SYMBOLS.keys.sort.each{ |v|
|
135
|
+
|
136
|
+
puts "\nFIELDS USED IN VERSION #{v}\n"
|
137
|
+
|
138
|
+
@@fieldsUsedN[v].keys.each { |field|
|
139
|
+
printf "\t%20s : %d\n", field, @@fieldsUsedN[v][field]
|
140
|
+
}
|
141
|
+
|
142
|
+
}
|
143
|
+
|
144
|
+
printf "\nMax v2 Tag Size was: %d , Average Tag Size was: %d\n" , @@sizeMax, (@@sizeSum / version2tagN)
|
145
|
+
puts "\n\ndone."
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# -*- coding: undecided -*-
|
2
|
+
|
3
|
+
# See also: http://stackoverflow.com/questions/7656950/read-id3-tags-of-remote-mp3-file-in-ruby-rails
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'awesome_print' # debugging only
|
7
|
+
|
8
|
+
require 'net/http'
|
9
|
+
require 'uri'
|
10
|
+
require 'id3'
|
11
|
+
require 'hexdump' # debugging only
|
12
|
+
|
13
|
+
# --------------------------------------------------------------------------------------------
|
14
|
+
|
15
|
+
def get_remote_id3v2_tag( file_url )
|
16
|
+
id3v2_tag_size = get_remote_id3v2_tag_size( file_url )
|
17
|
+
if id3v2_tag_size > 0
|
18
|
+
buffer = get_remote_bytes(file_url, id3v2_tag_size )
|
19
|
+
tag2 = ID3::Tag2.new
|
20
|
+
tag2.read_from_buffer( buffer )
|
21
|
+
return tag2
|
22
|
+
else
|
23
|
+
return nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_remote_id3v2_tag_size( file_url )
|
28
|
+
buffer = get_remote_bytes( file_url, 100 )
|
29
|
+
if buffer.bytesize > 0
|
30
|
+
return buffer.ID3v2_tag_size
|
31
|
+
else
|
32
|
+
return 0
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_remote_bytes( file_url, n)
|
37
|
+
uri = URI(file_url)
|
38
|
+
size = n # ID3v2 tags can be considerably larger, because of embedded album pictures
|
39
|
+
Net::HTTP.version_1_2 # make sure we use higher HTTP protocol version than 1.0
|
40
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
41
|
+
resp = http.get( file_url , {'Range' => "bytes=0-#{size-1}"} )
|
42
|
+
resp_code = resp.code.to_i
|
43
|
+
if (resp_code >= 200 && resp_code < 300) then
|
44
|
+
return resp.body
|
45
|
+
else
|
46
|
+
return ''
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# --------------------------------------------------------------------------------------------
|
51
|
+
|
52
|
+
file_url = 'http://www.unixgods.org/~tilo/ID3/example_mp3_file_with_id3v2.mp3' # please specify a URL here for testing
|
53
|
+
|
54
|
+
|
55
|
+
puts "\nRemote File: \"#{file_url}\""
|
56
|
+
|
57
|
+
puts "\ncontains ID3v2 tag of size: #{get_remote_id3v2_tag_size( file_url )} Bytes"
|
58
|
+
|
59
|
+
tag2 = get_remote_id3v2_tag( file_url )
|
60
|
+
|
61
|
+
puts "\nID3v3 Version: #{tag2.version}\n"
|
62
|
+
|
63
|
+
puts "\ncontains Frames:\n"
|
64
|
+
ap tag2.keys
|
65
|
+
|
66
|
+
puts "\nID3v2 Tag:\n"
|
67
|
+
|
68
|
+
ap( tag2 )
|
69
|
+
|
70
|
+
puts "\nID3v2 Hexdump:\n"
|
71
|
+
|
72
|
+
puts tag2.raw.hexdump(true)
|
73
|
+
|
74
|
+
|
data/id3.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "id3/version"
|
4
|
+
|
5
|
+
spec = Gem::Specification.new do |s|
|
6
|
+
s.name = 'id3'
|
7
|
+
s.version = ID3::VERSION
|
8
|
+
s.authors = ['Tilo Sloboda']
|
9
|
+
s.email = ['tilo.sloboda@gmail.com']
|
10
|
+
s.homepage = 'http://www.unixgods.org/~tilo/Ruby/ID3'
|
11
|
+
s.platform = Gem::Platform::RUBY
|
12
|
+
s.summary = 'A native ID3 tag library for Ruby, which does not depend on architecture-dependent C-libraries. It supports reading and writing ID3-tag versions 1.0, 1.1, and 2.2.x, 2,3.x, 2,4.x\n http://www.unixgods.org/~tilo/Ruby/ID3'
|
13
|
+
s.description = 'ID3 is a native ruby library for reading and writing ID3 tag versions 1.0, 1.1, and 2.2.x, 2,3.x, 2,4.x'
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
# s.files = Dir['docs/**/*'] + Dir['lib/*.rb'] + Dir['lib/id3/*.rb'] + Dir['lib/helpers/*.rb'] + ['LICENSE.html' , 'index.html', 'README.md' , 'CHANGES']
|
17
|
+
# s.test_files = FileList["{tests}/**/*test.rb"].to_a
|
18
|
+
s.has_rdoc = false
|
19
|
+
s.require_paths = ['lib']
|
20
|
+
s.autorequire = 'id3'
|
21
|
+
# s.extra_rdoc_files = ['README']
|
22
|
+
s.rdoc_options << '--title' << 'Native ID3 Ruby Library - uniform acecss to ID3v1 and ID3v2 tags'
|
23
|
+
s.add_dependency("activesupport", "~> 3.x")
|
24
|
+
# s.add_dependency("dependency", ">= 0.9.9")
|
25
|
+
# s.bindir = 'bin'
|
26
|
+
|
27
|
+
s.rubyforge_project = 'id3'
|
28
|
+
# s.rubyforge_project = ['none']
|
29
|
+
end
|
30
|
+
|
31
|
+
#Rake::GemPackageTask.new(spec) do |pkg|
|
32
|
+
# pkg.need_tar = true
|
33
|
+
#end
|
data/lib/id3.rb
CHANGED
@@ -14,6 +14,7 @@ require "helpers/hexdump" # only needed for debugging -> autoload
|
|
14
14
|
require 'id3/string_extensions' # adds ID3 methods to String
|
15
15
|
require 'id3/io_extensions' # adds ID3 methods to IO and File
|
16
16
|
|
17
|
+
require 'id3/version' # Gem Version
|
17
18
|
require 'id3/constants' # Constants used throughout the code
|
18
19
|
require 'id3/module_methods' # add ID3 methods to ID3 which operate on filenames
|
19
20
|
|
data/lib/id3/constants.rb
CHANGED
@@ -3,7 +3,7 @@ module ID3
|
|
3
3
|
# ----------------------------------------------------------------------------
|
4
4
|
# CONSTANTS
|
5
5
|
# ----------------------------------------------------------------------------
|
6
|
-
Version =
|
6
|
+
Version = VERSION
|
7
7
|
|
8
8
|
ID3v1tagSize = 128 # ID3v1 and ID3v1.1 have fixed size tags
|
9
9
|
ID3v1versionbyte = 125
|
data/lib/id3/version.rb
ADDED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: id3
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.
|
4
|
+
version: 1.0.0.pre6
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire: id3
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-08-
|
12
|
+
date: 2012-08-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
16
|
-
requirement: &
|
16
|
+
requirement: &5254080 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,58 +21,70 @@ dependencies:
|
|
21
21
|
version: 3.x
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *5254080
|
25
25
|
description: ID3 is a native ruby library for reading and writing ID3 tag versions
|
26
26
|
1.0, 1.1, and 2.2.x, 2,3.x, 2,4.x
|
27
|
-
email:
|
27
|
+
email:
|
28
|
+
- tilo.sloboda@gmail.com
|
28
29
|
executables: []
|
29
30
|
extensions: []
|
30
31
|
extra_rdoc_files: []
|
31
32
|
files:
|
32
|
-
-
|
33
|
-
-
|
34
|
-
-
|
35
|
-
-
|
33
|
+
- .gitignore
|
34
|
+
- CHANGES
|
35
|
+
- LICENSE.html
|
36
|
+
- README.md
|
37
|
+
- Rakefile
|
36
38
|
- docs/Class_AudioFile.html
|
37
|
-
- docs/
|
38
|
-
- docs/
|
39
|
-
- docs/ID3_comparison2.html
|
39
|
+
- docs/Class_Frame.html
|
40
|
+
- docs/Class_Tag1.html
|
40
41
|
- docs/Class_Tag2.html
|
41
|
-
- docs/Module_ID3.html
|
42
|
-
- docs/id3.html
|
43
42
|
- docs/ID3-Standards/id3v2-00.html
|
43
|
+
- docs/ID3-Standards/id3v2-00.txt
|
44
|
+
- docs/ID3-Standards/id3v2.3.0.html
|
45
|
+
- docs/ID3-Standards/id3v2.3.0.txt
|
46
|
+
- docs/ID3-Standards/id3v2.4.0-changes.html
|
44
47
|
- docs/ID3-Standards/id3v2.4.0-changes.txt
|
45
48
|
- docs/ID3-Standards/id3v2.4.0-frames.html
|
46
|
-
- docs/ID3-Standards/id3v2.3.0.html
|
47
49
|
- docs/ID3-Standards/id3v2.4.0-frames.txt
|
48
|
-
- docs/ID3-Standards/id3v2.4.0-structure.txt
|
49
|
-
- docs/ID3-Standards/id3v2.4.0-changes.html
|
50
|
-
- docs/ID3-Standards/id3v2.3.0.txt
|
51
50
|
- docs/ID3-Standards/id3v2.4.0-structure.html
|
52
|
-
- docs/ID3-Standards/id3v2-
|
53
|
-
- docs/
|
51
|
+
- docs/ID3-Standards/id3v2.4.0-structure.txt
|
52
|
+
- docs/ID3_comparison.html
|
53
|
+
- docs/ID3_comparison2.html
|
54
|
+
- docs/ID3v2_frames_comparison.html
|
55
|
+
- docs/ID3v2_frames_overview.txt
|
56
|
+
- docs/Module_ID3.html
|
57
|
+
- docs/hexdump.rb
|
58
|
+
- docs/id3.html
|
59
|
+
- docs/index.html
|
60
|
+
- examples/id3_statistics_with_Audiofile.rb
|
61
|
+
- examples/mp3/example_mp3_file_with_id3v2_2_0.mp3
|
62
|
+
- examples/mp3/rheeeeet.mp3
|
63
|
+
- examples/old/example2.rb
|
64
|
+
- examples/old/examples.rb
|
65
|
+
- examples/old/id3statistics.rb
|
66
|
+
- examples/read_remote_id3v2_tag.rb
|
67
|
+
- id3.gemspec
|
68
|
+
- index.html
|
69
|
+
- lib/helpers/hash_extensions.rb
|
70
|
+
- lib/helpers/hexdump.rb
|
71
|
+
- lib/helpers/invert_hash.rb
|
72
|
+
- lib/helpers/recursive_helper.rb
|
73
|
+
- lib/helpers/restricted_ordered_hash.rb
|
74
|
+
- lib/helpers/ruby_1.8_1.9_compatibility.rb
|
54
75
|
- lib/id3.rb
|
55
|
-
- lib/id3/
|
56
|
-
- lib/id3/id3.rb
|
76
|
+
- lib/id3/audiofile.rb
|
57
77
|
- lib/id3/constants.rb
|
58
|
-
- lib/id3/tag2.rb
|
59
78
|
- lib/id3/frame.rb
|
79
|
+
- lib/id3/frame_array.rb
|
60
80
|
- lib/id3/generic_tag.rb
|
61
|
-
- lib/id3/
|
81
|
+
- lib/id3/id3.rb
|
62
82
|
- lib/id3/io_extensions.rb
|
63
|
-
- lib/id3/
|
64
|
-
- lib/id3/frame_array.rb
|
83
|
+
- lib/id3/module_methods.rb
|
65
84
|
- lib/id3/string_extensions.rb
|
66
|
-
- lib/
|
67
|
-
- lib/
|
68
|
-
- lib/
|
69
|
-
- lib/helpers/recursive_helper.rb
|
70
|
-
- lib/helpers/hash_extensions.rb
|
71
|
-
- lib/helpers/restricted_ordered_hash.rb
|
72
|
-
- LICENSE.html
|
73
|
-
- index.html
|
74
|
-
- README.md
|
75
|
-
- CHANGES
|
85
|
+
- lib/id3/tag1.rb
|
86
|
+
- lib/id3/tag2.rb
|
87
|
+
- lib/id3/version.rb
|
76
88
|
homepage: http://www.unixgods.org/~tilo/Ruby/ID3
|
77
89
|
licenses: []
|
78
90
|
post_install_message:
|