【问题标题】:Read ID3 Tags of Remote MP3 File in Ruby/Rails?在 Ruby/Rails 中读取远程 MP3 文件的 ID3 标签?
【发布时间】:2011-12-01 04:47:33
【问题描述】:

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

JavaSilverlight 中已经提出了这个问题,但没有 Ruby。

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

【问题讨论】:

  • ID3 v2 标签位于文件的开头 - 以支持流式传输 - 这意味着下面的答案可以正常工作..

标签: ruby mp3 id3


【解决方案1】:

您至少必须下载文件的最后一个块,其中包含 ID3 标签——请参阅 ID3 标签定义...

如果您可以访问远程文件系统上的文件,则可以这样做。这个远程,然后传回ID3标签

编辑:

我在考虑 ID3 v1 标签 -- 版本 2 标签在前面。

【讨论】:

  • 如何使用 Ruby 下载 mp3 文件的最后几块?
  • 这仅适用于 ID3 版本 1 的标签——目前这些标签已经过时了。
【解决方案2】:

您使用的是哪个 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

例如:

 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

【讨论】:

  • HTTP 支持下载文件的特定区域。从理论上讲,一个人可以只下载文件的最后一个块,获取标签......需要弄清楚这是如何完成的。
  • 可以通过在http请求期间传递“Range”头来请求文件的中间:stackoverflow.com/questions/587559/…
  • 到目前为止,我已经设法检查 ID3 v1 和 v2 标签,解析 v1 标签并获取 v2 标签块。还不能手动解析 v2 标签。 ID3v2 如何标记“帧”的结束?
  • @Jordan:你检查过 ID3 库 'id3' 吗?在 GitHub 上
  • 正在调查。感谢您对此的所有帮助。 =^]
猜你喜欢
  • 1970-01-01
  • 2011-05-02
  • 2011-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多