在 Ruby/Rails 中读取远程 MP3 文件的 ID3 标签?

发布于 2024-12-07 20:33:51 字数 386 浏览 1 评论 0原文

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

这个问题已在 JavaSilverlight,但没有 Ruby。

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

Using Ruby, how can one parse the ID3 tags of remote mp3 files without downloading the entire file to disk?

This question has been asked in Java and Silverlight, but no Ruby.

Edit: Looking at the Java answer, it seems as though it's possible (HTTP supports it) to download just the tail end of a file, which is where the tags are. Can this be done in Ruby?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一张白纸 2024-12-14 20:33:51

您使用的是哪个 Ruby 版本?

您尝试读取哪个 ID3 标签版本?

ID3v1 标签位于文件末尾,在最后 128 字节。使用 Net::HTTP 似乎不可能向前查找文件末尾并仅读取最后 N 个字节。如果你尝试这样做,使用
headers = {"范围" =>; "bytes=128-"} ,它似乎总是下载完整的文件。 resp.body.size =>;文件大小 。但没有什么大的损失,因为ID3版本1在这一点上已经过时了,因为它有局限性,例如固定长度格式,只有ASCII文本,...)。 iTunes 使用 ID3 版本 2.2.0。

ID3v2 标签位于文件的开头 - 支持流式传输 - 您可以通过 HTTP 协议下载 MP3 文件的初始部分,其中包含 ID3v2 标头 >= 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

一些如何下载的示例零件文件可以在这里找到:

但请注意,似乎无法“在中间”开始下载

如何通过 HTTP 下载二进制文件?

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

which Ruby version are you using?

which ID3 Tag version are you trying to read?

ID3v1 tags are at the end of a file, in the last 128 bytes. With Net::HTTP it doesn't seem to be possible to seek forward towards the end of the file and read only the last N bytes. If you try that, using
headers = {"Range" => "bytes=128-"} , it always seems to download the complete file. resp.body.size => file-size . But no big loss, because ID3 version 1 is pretty much outdated at this point because of it's limitations, such as fixed length format, only ASCII text, ...). iTunes uses ID3 version 2.2.0.

ID3v2 tags are at the beginning of a file - to support streaming - you can download the initial part of the MP3 file, which contains the ID3v2 header, via HTTP protocol >= 1.1

The short answer:

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"]    ................

The long answer looks something like this: (you'll need id3 library version 1.0.0_pre or newer)

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

See:

http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35

http://en.wikipedia.org/wiki/Byte_serving

some examples how to download in parts files can be found here:

but please note that there seems to be no way to start downloading "in the middle"

How do I download a binary file over HTTP?

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

往日 2024-12-14 20:33:51

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

如果您有权访问远程文件系统上的文件,则可以这样做。远程执行此操作,然后传回 ID3 标签

编辑:

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

you would at least have to download the last blocks of the file, which contain the ID3 tags -- see ID3 tag definitions...

if you have access to the files on the remote file system, you could do. this remotely, and then transfer back the ID3 tags

Edit:

I was thinking of ID3 v1 tags -- version 2 tags are in the front.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文