使用Ruby,如何解析远程mp3文件的ID3标签,而不需要将整个文件下载到磁盘上?
这个问题已经在Java和Silverlight中提出过,但没有关于Ruby的回答。 编辑:查看Java的回答,似乎可以(HTTP支持)只下载文件的尾部,也就是标签所在的位置。在Ruby中能实现吗?
这个问题已经在Java和Silverlight中提出过,但没有关于Ruby的回答。 编辑:查看Java的回答,似乎可以(HTTP支持)只下载文件的尾部,也就是标签所在的位置。在Ruby中能实现吗?
你正在使用哪个Ruby版本?
你正在尝试读取哪个ID3标签版本?
ID3v1标签位于文件末尾的最后128字节。使用Net::HTTP时,似乎无法向前寻找到文件末尾并仅读取最后N个字节。如果您尝试这样做,使用headers = {"Range" => "bytes=128-"}
,它似乎总是下载完整的文件。resp.body.size => file-size
。但没有太大损失,因为ID3版本1在目前已经过时,因为它有一些限制,例如固定长度格式,只支持ASCII文本等)。iTunes使用ID3版本2.2.0。
ID3v2标签位于文件开头,以支持流媒体。您可以通过HTTP协议>= 1.1下载包含ID3v2标头的MP3文件的初始部分。
简短回答:
require 'net/http'
require 'uri'
require 'id3' # id3 RUby library
require 'hexdump'
file_url = 'http://example.com/filename.mp3'
uri = URI(file_url)
size = 1000 # ID3v2 tags can be considerably larger, because of embedded album pictures
Net::HTTP.version_1_2 # make sure we use higher HTTP protocol version than 1.0
http = Net::HTTP.new(uri.host, uri.port)
resp = http.get( file_url , {'Range' => "bytes=0-#{size}"} )
# should check the response status codes here..
if resp.body =~ /^ID3/ # we most likely only read a small portion of the ID3v2 tag..
# file has ID3v2 tag
puts resp.body.hexdump
tag2 = ID3::Tag2.new
tag2.read_from_buffer( resp.body )
@id3_tag_size = tag2.ID3v2tag_size # that's the size of the whole ID3v2 tag
# we should now re-fetch the tag with the correct / known size
# ...
end
e.g.:
index 0 1 2 3 4 5 6 7 8 9 A B C D E F
00000000 ["49443302"] ["00000000"] ["11015454"] ["3200000d"] ID3.......TT2...
00000010 ["004b6167"] ["75796120"] ["48696d65"] ["00545031"] .Kaguya Hime.TP1
00000020 ["00000e00"] ["4a756e6f"] ["20726561"] ["63746f72"] ....Juno reactor
00000030 ["0054414c"] ["00001100"] ["4269626c"] ["65206f66"] .TAL....Bible of
00000040 ["20447265"] ["616d7300"] ["54524b00"] ["00050036"] Dreams.TRK....6
00000050 ["2f390054"] ["59450000"] ["06003139"] ["39370054"] /9.TYE....1997.T
00000060 ["434f0000"] ["1300456c"] ["65637472"] ["6f6e6963"] CO....Electronic
00000070 ["612f4461"] ["6e636500"] ["54454e00"] ["000d0069"] a/Dance.TEN....i
00000080 ["54756e65"] ["73207632"] ["2e300043"] ["4f4d0000"] Tunes v2.0.COM..
00000090 ["3e00656e"] ["67695475"] ["6e65735f"] ["43444442"] >.engiTunes_CDDB
000000a0 ["5f494473"] ["00392b36"] ["34374334"] ["36373436"] _IDs.9+647C46746
000000b0 ["38413234"] ["38313733"] ["41344132"] ["30334544"] 8A248173A4A203ED
000000c0 ["32323034"] ["4341422b"] ["31363333"] ["39390000"] 2204CAB+163399..
000000d0 ["00000000"] ["00000000"] ["00000000"] ["00000000"] ................
长话短说:(您需要使用id3库版本1.0.0_pre或更高版本)
require 'net/http'
require 'uri'
require 'id3' # id3 RUby library
require 'hexdump'
file_url = 'http://example.com/filename.mp3'
def get_remote_id3v2_tag( file_url ) # you would call this..
id3v2tag_size = get_remote_id3v2_tag_size( file_url )
if id3v2tag_size > 0
buffer = get_remote_bytes(file_url, id3v2tag_size )
tag2 = ID3::Tag2.new
tag2.read_from_buffer( buffer )
return tag2
else
return nil
end
end
private
def get_remote_id3v2_tag_size( file_url )
buffer = get_remote_bytes( file_url, 100 )
if buffer.bytesize > 0
return buffer.ID3v2tag_size
else
return 0
end
end
private
def get_remote_bytes( file_url, n)
uri = URI(file_url)
size = n # ID3v2 tags can be considerably larger, because of embedded album pictures
Net::HTTP.version_1_2 # make sure we use higher HTTP protocol version than 1.0
http = Net::HTTP.new(uri.host, uri.port)
resp = http.get( file_url , {'Range' => "bytes=0-#{size-1}"} )
resp_code = resp.code.to_i
if (resp_code >= 200 && resp_code < 300) then
return resp.body
else
return ''
end
end
get_remote_id3v2_tag_size( file_url )
=> 2262
请参见:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35
http://en.wikipedia.org/wiki/Byte_serving
以下是一些如何分部分下载文件的示例:
但请注意,似乎没有办法“从中间”开始下载
如果你想要至少下载文件的最后几个块,才能获取包含ID3标签的信息--请参考ID3标签定义......
如果你可以访问远程文件系统中的文件,你可以在远程执行此操作,然后传输回ID3标签。
编辑:
我想的是ID3 v1标签--版本2的标签在前面。