如何快速读取MP3网站上MP3文件的ID3信息?(200分)

  • 主题发起人 主题发起人 Andersonchan
  • 开始时间 开始时间
A

Andersonchan

Unregistered / Unconfirmed
GUEST, unregistred user!
我想做一个MP3的搜索程序,可如何才能快速得到各大MP3网站的MP3的ID3信息?不可能把每个
MP3文件都DOWN下来吧?或者只下载ID3部分,或者能够直接读取?关键是快!
 
关注你的问题!
 
下载文件指定部分
1/了解HTTP下载的实现
2/了解MP3中ID3的位置
即可[:D]
 
以字符流形式
读取MP3尾128个字节
 
我晕~~~~~~~~楼上的和没说一样,我不是不知道本地的ID3如何读,我说的是网络上,用HTTP提供下载的MP3,可否从任意位置开始传输!比如尾128字节,
还有HTTP提供的MP3如何搜索?
 
写了段,不过只是对Http的,其它的不知了。:)
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TID3 = record
Tag: array[0..2] of Char; // TAG
Title: array[0..$1D] of Char; // 03..20
Artist: array[0..$1D] of Char; // 21..3e
Album: array[0..$1D] of Char; // 3f..5c
Year: array[0..3] of Char; // 5d..60
Comment: array[0..$1C] of Char; // 61..7d
Track: Byte; // 7e
Genre: Byte; // 7f
end;

TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
Memo2: TMemo;
procedure Button1Click(Sender: TObject);
private
procedure AddID3(MP3URL: string; ID3: TID3);
end;

var
Form1: TForm1;

implementation

uses ScktComp, WinSock;
{$R *.dfm}
const
CRLF = #13#10;
SizeID3 = SizeOf(TID3);

procedure ExtractHostAndFileName(AURL: string; var AHost, AFileName: string;
APort: PString = nil);
const
HttpHead = 'http://';
HttpHeadLen = Length(HttpHead);
var
I: Integer;
begin
AHost := AURL;
I := AnsiPos(HttpHead, AURL);
if I <> 0 then
AHost := Copy(AHost, I + HttpHeadLen, MaxInt);
I := AnsiPos('/', AHost);
while I <> 0 do
begin
AHost := Copy(AHost, 1, I - 1);
I := AnsiPos('/', AHost);
end;
I := Pos(AHost, AURL) + Length(AHost);
AFileName := Copy(AURL, i, MaxInt);
I := Pos(':', AHost);
if I <> 0 then
begin
if Assigned(APort) then
APort^ := Copy(AHost, I + 1, MaxInt);
AHost := Copy(AHost, 1, I - 1);
end;

end;

type
TGetMP3ID3 = class(TThread)
private
FID3: TID3;
FMP3URL: string;
FList: TStrings;
procedure AddID3;
procedure GetMP3Data(Socket: TCustomWinSocket;
Host, FileName: string);
public
procedure Execute; override;
constructor Create(MP3List: string);
end;

{ TGetMP3ID3 }

procedure TGetMP3ID3.AddID3;
begin
Form1.AddID3(FMP3URL, FID3);
end;

constructor TGetMP3ID3.Create(MP3List: string);
begin
FList := TStringList.Create;
FList.Text := MP3List;
FreeOnTerminate := True;
inherited Create(False);
end;

procedure TGetMP3ID3.GetMP3Data(Socket: TCustomWinSocket;
Host, FileName: string);
const
FileContentLen = 'content-length: ';
UserAgent =
'User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705)';
RequestFileHead =
'HEAD %s HTTP/1.1' + CRLF +
'Pragma: no-cache' + CRLF +
'Cache-Control: no-cache' + CRLF +
UserAgent + CRLF +
'Host: %s' + CRLF + CRLF;
RequestGetMP3ID3 =
'GET %s HTTP/1.1' + CRLF +
'Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*' + CRLF +
UserAgent + CRLF +
'RANGE: bytes=%d-' + CRLF +
'Host: %s' + CRLF + CRLF;

function WaitForSocket(Timeout: Integer): Boolean;
var
FDSet: TFDSet;
TimeVal: TTimeVal;
begin
TimeVal.tv_sec := Timeout;
TimeVal.tv_usec := 0;
FD_ZERO(FDSet);
FD_SET(Socket.SocketHandle, FDSet);
Result := WinSock.select(0, @FDSet, nil, nil, @TimeVal) > 0;
end;

function ReceiveLine: string;
var
C: Char;
RetLen: Integer;
begin
Result := '';
while Socket.Connected do
begin
RetLen := Socket.ReceiveBuf(C, 1);
if RetLen = 0 then
raise ESocketError.Create('Socket Read error');
Result := Result + C;
if AnsiPos(CRLF, Result) > 0 then break;
end;
end;

function SendCommand(Command: string): string;
var
Data: string;
begin
Result := '';
Socket.SendBuf(Command[1], Length(Command));
while Socket.Connected and WaitForSocket(5) do
begin
Data := ReceiveLine;
if Data = CRLF then
break else
Result := Result + Data;
end;
end;

function GetFileSize(Data: string): Integer;
var
I, Start: Integer;
List: TStrings;
begin
Result := -1;
List := TStringList.Create;
try
List.Text := Data;
for I := 0 to List.Count - 1 do
begin
Start := AnsiPos(FileContentLen, LowerCase(List));
if Start > 0 then
begin
Result := StrToInt(Copy(List, Length(FileContentLen) + 1, MaxInt));
break;
end;
end;
finally
List.Free;
end;
end;

//修改于: 11-10 21:55,这回不会再错了。[:D]
var
Data: string;
C: array [0..127] of Char;
RetLen, FileSize: Integer;
begin
Data := SendCommand(Format(RequestFileHead, [FileName, Host]));
FileSize := GetFileSize(Data);
Data := SendCommand(Format(RequestGetMP3ID3, [FileName, FileSize - 128, Host]));
if AnsiPos('content-range:', LowerCase(Data)) > 0 then
begin
FillChar(C, SizeOf(C), 0);
RetLen := Socket.ReceiveBuf(C, SizeOf(C));
if RetLen = 0 then
raise ESocketError.Create('Socket read error');
Move(C, FID3, RetLen);
end;
end;

procedure TGetMP3ID3.Execute;
var
I, Timeout: Integer;
Socket: TClientWinSocket;
Host, Port, FileName: string;
begin
Socket := TClientWinSocket.Create(INVALID_SOCKET);
try
Socket.ClientType := ctBlocking;
for I := 0 to FList.Count - 1 do
begin
if Socket.Connected then Socket.Close;
FMP3URL := FList;
FillChar(FID3, SizeID3, 0);
Port := '80';
ExtractHostAndFileName(FMP3URL, Host, FileName, @Port);
try
Socket.Open(Host, Host, '', StrToInt(Port), True);
// 设个接收Timeout,不然程序死劲的等待就不好了,
Timeout := 5000; //这是豪秒数
setsockopt(Socket.SocketHandle, SOL_SOCKET, SO_RCVTIMEO, @Timeout, SizeOf(Integer));
GetMP3Data(Socket, Host, FileName);
Synchronize(AddID3);
except
on E: Exception do
begin //错误自已处理了。
FMp3URL := 'Error: ' + E.Message;
Synchronize(AddID3);
end;
end;
end;
finally
Socket.Close;
Socket.Free;
end;
end;

{ TForm1 }

procedure TForm1.AddID3(MP3URL: string; ID3: TID3);
var
S: string;
begin
with ID3 do
S :=
'MP3: ' + MP3URL + CRLF +
'Artist: ' + Artist + CRLF +
'Title: ' + Title + CRLF +
'Album: ' + Album + CRLF +
'Year: ' + Year + CRLF +
'Comment: ' + Comment + CRLF +
'Track: ' + IntTOStr(Track) + CRLF +
'Genre: ' + IntToStr(Genre);

Memo2.Lines.Add(S);
Memo2.Lines.Add('')
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
TGetMP3ID3.Create(Memo1.Lines.Text);
end;

end.

窗体很简单,两个Memo,一个Button,一个Memo是存放MP3的URL的,一个是返回信息
object Form1: TForm1
Left = 192
Top = 107
Width = 544
Height = 375
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Button1: TButton
Left = 0
Top = 64
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 0
OnClick = Button1Click
end
object Memo1: TMemo
Left = 96
Top = 16
Width = 433
Height = 121
Lines.Strings = (
'http://music.jztele.com/mp3/sunyanzi/syz/10.mp3'

'http://202.99.170.4/music101/mp3/sunyanzi/woyaodexingfu/796_3614' +
'_37181.mp3')
TabOrder = 1
end
object Memo2: TMemo
Left = 96
Top = 144
Width = 433
Height = 201
ScrollBars = ssBoth
TabOrder = 2
end
end
 
当然错误不是不可避免的[:D],有时连接不上的时候,有密码或端口不是80的时候,读的时候不是太正确。
先这样了[:D][:D][:D][:D][:D][:D][:D]
 
谢谢楼上的兄弟,但代码好像只在连接正确的时候才能读出,此GetMP3Data(Socket, Host, FileName);函数经常出错,
这些没关系,我来改,可是,如何才能在网站中搜索到MEMO1中的这些链接呢?
http://music.jztele.com/mp3/sunyanzi/syz/10.mp3
 
MP3: http://music.jztele.com/mp3/sunyanzi/syz/10.mp3
Artist:
Title:
Album:
Year:
Comment:
Track: 0
Genre: 0
得不到,如果一个MP3没有ID3的话,也就是为空了,所以它也得不到,正规的MP3一般有ID3,但像我们从CD/VCD压缩的你说有没ID3,肯定没嘛

程序改了,那程序上面有两句汉字就是改了的。

Search MP3目录也简单,不过你要有浏览的权限,不然没法,具体可以看看flashget.拿自已本地来试。
 
谢谢,改了的代码果然好得多,Search mp3 目录是不是用FTP?我Search的是Mp3大站的目录没有权限怎么办?
用匿名可以不?可否搜索.html文件?
 
具体我没做过,我是看FlashGet 的的站点浏览器可以,那我想应该HTTP/FTP是可以的,但
我也不知如何做,我只是试过本地开个目录,然后用它来看。看看它的命令(速度模式为
最小,就能看本地,不然太快)

老兄,应该从战略上藐视它嘛。。。。
这是老毛同志教导我们的嘛。。。
 
谢谢,给分了!如有问题再来请教 copy_paste 兄弟了!
 
接受答案了.
 
后退
顶部