📄 id3v2.pas
字号:
end;
{ --------------------------------------------------------------------------- }
function ExtractGenre(const GenreString: string): string;
begin
{ Extract genre from string }
Result := Trim(GenreString);
if Pos(')', Result) > 0 then Delete(Result, 1, LastDelimiter(')', Result));
end;
{ --------------------------------------------------------------------------- }
function ExtractComment(const CommentString: string): string;
var
Comment: string;
begin
{ Extract comment from string }
Comment := CommentString;
Delete(Comment, 1, 4);
Delete(Comment, 1, Pos(#0, Comment));
Result := Trim(Comment);
end;
{ --------------------------------------------------------------------------- }
function ExtractLink(const LinkString: string): string;
var
Link: string;
begin
{ Extract URL link from string }
Link := LinkString;
Delete(Link, 1, 1);
Delete(Link, 1, Pos(#0, Link));
Result := Trim(Link);
end;
{ --------------------------------------------------------------------------- }
procedure BuildHeader(var Tag: TagInfo);
var
Iterator, TagSize: Integer;
begin
{ Build tag header }
Tag.ID := ID3V2_ID;
Tag.Version := TAG_VERSION_2_3;
Tag.Revision := 0;
Tag.Flags := 0;
TagSize := 0;
for Iterator := 1 to ID3V2_FRAME_COUNT do
if Tag.Frame[Iterator] <> '' then
Inc(TagSize, Length(Tag.Frame[Iterator]) + 11);
{ Convert tag size }
Tag.Size[1] := TagSize div $200000;
Tag.Size[2] := TagSize div $4000;
Tag.Size[3] := TagSize div $80;
Tag.Size[4] := TagSize mod $80;
end;
{ --------------------------------------------------------------------------- }
function RebuildFile(const FileName: string; TagData: TStream): Boolean;
var
Tag: TagInfo;
Source, Destination: TFileStream;
BufferName: string;
begin
{ Rebuild file with old file data and new tag data (optional) }
Result := false;
if (not FileExists(FileName)) or (FileSetAttr(FileName, 0) <> 0) then exit;
if not ReadHeader(FileName, Tag) then exit;
if (TagData = nil) and (Tag.ID <> ID3V2_ID) then exit;
try
{ Create file streams }
BufferName := FileName + '~';
Source := TFileStream.Create(FileName, fmOpenRead or fmShareExclusive);
Destination := TFileStream.Create(BufferName, fmCreate);
{ Copy data blocks }
if Tag.ID = ID3V2_ID then Source.Seek(GetTagSize(Tag), soFromBeginning);
if TagData <> nil then Destination.CopyFrom(TagData, 0);
Destination.CopyFrom(Source, Source.Size - Source.Position);
{ Free resources }
Source.Free;
Destination.Free;
{ Replace old file and delete temporary file }
if (DeleteFile(FileName)) and (RenameFile(BufferName, FileName)) then
Result := true
else
raise Exception.Create('');
except
{ Access error }
if FileExists(BufferName) then DeleteFile(BufferName);
end;
end;
{ --------------------------------------------------------------------------- }
function SaveTag(const FileName: string; Tag: TagInfo): Boolean;
var
TagData: TStringStream;
Iterator, FrameSize: Integer;
begin
{ Build and write tag header and frames to stream }
TagData := TStringStream.Create('');
BuildHeader(Tag);
TagData.Write(Tag, 10);
for Iterator := 1 to ID3V2_FRAME_COUNT do
if Tag.Frame[Iterator] <> '' then
begin
TagData.WriteString(ID3V2_FRAME_NEW[Iterator]);
FrameSize := Swap32(Length(Tag.Frame[Iterator]) + 1);
TagData.Write(FrameSize, SizeOf(FrameSize));
TagData.WriteString(#0#0#0 + Tag.Frame[Iterator]);
end;
{ Rebuild file with new tag data }
Result := RebuildFile(FileName, TagData);
TagData.Free;
end;
{ ********************** Private functions & procedures ********************* }
procedure TID3v2.FSetTitle(const NewTitle: string);
begin
{ Set song title }
FTitle := Trim(NewTitle);
end;
{ --------------------------------------------------------------------------- }
procedure TID3v2.FSetArtist(const NewArtist: string);
begin
{ Set artist name }
FArtist := Trim(NewArtist);
end;
{ --------------------------------------------------------------------------- }
procedure TID3v2.FSetAlbum(const NewAlbum: string);
begin
{ Set album title }
FAlbum := Trim(NewAlbum);
end;
{ --------------------------------------------------------------------------- }
procedure TID3v2.FSetTrack(const NewTrack: Byte);
begin
{ Set track number }
FTrack := NewTrack;
end;
{ --------------------------------------------------------------------------- }
procedure TID3v2.FSetYear(const NewYear: string);
begin
{ Set release year }
FYear := Trim(NewYear);
end;
{ --------------------------------------------------------------------------- }
procedure TID3v2.FSetGenre(const NewGenre: string);
begin
{ Set genre name }
FGenre := Trim(NewGenre);
end;
{ --------------------------------------------------------------------------- }
procedure TID3v2.FSetComment(const NewComment: string);
begin
{ Set comment }
FComment := Trim(NewComment);
end;
{ --------------------------------------------------------------------------- }
procedure TID3v2.FSetComposer(const NewComposer: string);
begin
{ Set composer name }
FComposer := Trim(NewComposer);
end;
{ --------------------------------------------------------------------------- }
procedure TID3v2.FSetEncoder(const NewEncoder: string);
begin
{ Set encoder name }
FEncoder := Trim(NewEncoder);
end;
{ --------------------------------------------------------------------------- }
procedure TID3v2.FSetCopyright(const NewCopyright: string);
begin
{ Set copyright information }
FCopyright := Trim(NewCopyright);
end;
{ --------------------------------------------------------------------------- }
procedure TID3v2.FSetLanguage(const NewLanguage: string);
begin
{ Set language }
FLanguage := Trim(NewLanguage);
end;
{ --------------------------------------------------------------------------- }
procedure TID3v2.FSetLink(const NewLink: string);
begin
{ Set URL link }
FLink := Trim(NewLink);
end;
{ ********************** Public functions & procedures ********************** }
constructor TID3v2.Create;
begin
{ Create object }
inherited;
ResetData;
end;
{ --------------------------------------------------------------------------- }
procedure TID3v2.ResetData;
begin
{ Reset all variables }
FExists := false;
FVersionID := 0;
FSize := 0;
FTitle := '';
FArtist := '';
FAlbum := '';
FTrack := 0;
FYear := '';
FGenre := '';
FComment := '';
FComposer := '';
FEncoder := '';
FCopyright := '';
FLanguage := '';
FLink := '';
end;
{ --------------------------------------------------------------------------- }
function TID3v2.ReadFromFile(const FileName: string): Boolean;
var
Tag: TagInfo;
begin
{ Reset data and load header from file to variable }
ResetData;
Result := ReadHeader(FileName, Tag);
{ Process data if loaded and header valid }
if (Result) and (Tag.ID = ID3V2_ID) then
begin
FExists := true;
{ Fill properties with header data }
FVersionID := Tag.Version;
FSize := GetTagSize(Tag);
{ Get information from frames if version supported }
if (FVersionID in [TAG_VERSION_2_2..TAG_VERSION_2_4]) and (FSize > 0) then
begin
if FVersionID > TAG_VERSION_2_2 then ReadFramesNew(FileName, Tag)
else ReadFramesOld(FileName, Tag);
FTitle := GetContent(Tag.Frame[1], Tag.Frame[15]);
FArtist := GetContent(Tag.Frame[2], Tag.Frame[14]);
FAlbum := GetContent(Tag.Frame[3], Tag.Frame[16]);
FTrack := ExtractTrack(Tag.Frame[4]);
FYear := ExtractYear(Tag.Frame[5], Tag.Frame[13]);
FGenre := ExtractGenre(Tag.Frame[6]);
FComment := ExtractComment(Tag.Frame[7]);
FComposer := Trim(Tag.Frame[8]);
FEncoder := Trim(Tag.Frame[9]);
FCopyright := Trim(Tag.Frame[10]);
FLanguage := Trim(Tag.Frame[11]);
FLink := ExtractLink(Tag.Frame[12]);
end;
end;
end;
{ --------------------------------------------------------------------------- }
function TID3v2.SaveToFile(const FileName: string): Boolean;
var
Tag: TagInfo;
begin
{ Prepare tag data and save to file }
FillChar(Tag, SizeOf(Tag), 0);
Tag.Frame[1] := FTitle;
Tag.Frame[2] := FArtist;
Tag.Frame[3] := FAlbum;
if FTrack > 0 then Tag.Frame[4] := IntToStr(FTrack);
Tag.Frame[5] := FYear;
Tag.Frame[6] := FGenre;
if FComment <> '' then Tag.Frame[7] := 'eng' + #0 + FComment;
Tag.Frame[8] := FComposer;
Tag.Frame[9] := FEncoder;
Tag.Frame[10] := FCopyright;
Tag.Frame[11] := FLanguage;
if FLink <> '' then Tag.Frame[12] := #0 + FLink;
Result := SaveTag(FileName, Tag);
end;
{ --------------------------------------------------------------------------- }
function TID3v2.RemoveFromFile(const FileName: string): Boolean;
begin
{ Remove tag from file }
Result := RebuildFile(FileName, nil);
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -