2011-10-05 99 views
4

使用Ruby,如何在不将整个文件下载到磁盘的情况下解析远程mp3文件的ID3标签?在Ruby/Rails中阅读远程MP3文件的ID3标签?

已在JavaSilverlight中询问此问题,但未提供Ruby。

编辑:看看Java的答案,它似乎有可能(HTTP支持它)只下载文件的尾端,这是标签的位置。这可以在Ruby中完成吗?

+0

ID3 V2标签是在文件的开头 - 以支持流 - 这意味着下面的答案工作正常.. – Tilo

回答

4

您正在使用哪个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标签是在文件的开头 - 以支持流 - 可以下载MP3文件,其中包含的ID3v2头的初始部分,通过HTTP协议> = 1.1

短答案:

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 

如:

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

一些例子来说明如何在部分下载文件可以在这里找到:

但请注意,似乎没有办法开始下载“中间”

How do I download a binary file over HTTP?

http://unixgods.org/~tilo/Ruby/ID3/docs/index.html

+1

HTTP支持下载文件的特定区域。从理论上讲,只能下载文件的最后一个块,得到标签......需要弄清楚这是如何完成的。 –

+0

可以通过在http请求期间传递“Range”头来请求文件的中间:http://stackoverflow.com/questions/587559/ruby-how-to-make-an-http-get-with-modified -headers –

+0

您试图阅读哪些ID3标签版本? 2.x? – Tilo

2

你至少需要下载文件的最后一个块,其中包括ID3标签 - 见ID3标签定义...

如果你有机会到文件的远程文件系统上,你可以做。这种远程,然后传送回ID3标签

编辑:

我想ID3 V1标签 - 2个标签在了前面。

+0

怎样下载mp3文件的最后一个块使用Ruby? –

+0

这只适用于ID3版本1标签 - 目前已经过时了。 – Tilo