In this project, we are opening MP3 files using the component 3delite.hu =- ID3v2 Library, and adding the MP3 files metadata to a ListView.
What I would like to accomplish.
When selecting multiple items in the listview, the edit fields will show <multi>, meaning that multiple items have been selected. If you try and edit anything and save it, this will result in the files getting the wrong data sent to them.
What I would like to ask is this.
How can you select multiple items, edit certain areas, and have it update each file individually?
Below is the code for this project.
LoadIt.pas
unit LoadIt;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, ComCtrls, StdCtrls, ID3v1Library, ID3v2Library, UITypes, StrUtils;
type
TForm1 = class(TForm)
SidePanel: TPanel;
MainPanel: TPanel;
ListView1: TListView;
OpenDialog1: TOpenDialog;
strTitle: TEdit;
strArtist: TEdit;
Label1: TLabel;
Label2: TLabel;
strAlbum: TEdit;
Label3: TLabel;
strTrack: TEdit;
Label5: TLabel;
TopPanel: TPanel;
Button8: TButton;
Edit1: TEdit;
Label4: TLabel;
strPath: TEdit;
saveButton: TButton;
Memo1: TMemo;
SelectedLabel: TLabel;
Button1: TButton;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure Button8Click(Sender: TObject);
procedure ListView1SelectItem(Sender: TObject; Item: TListItem;
Selected: Boolean);
procedure saveButtonClick(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
ID3v1Tag: TID3v1Tag = nil;
ID3v2Tag: TID3v2Tag = nil;
CurrentAPICIndex: Integer = - 1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var
Column: TListColumn;
begin
TopPanel.Align := alTop;
SidePanel.Align := alLeft;
MainPanel.Align := alClient;
ListView1.Align := alClient;
ID3v1Tag := TID3v1Tag.Create;
ID3v2Tag := TID3v2Tag.Create;
Column := ListView1.Columns.Add;
Column.Caption := 'Track ID';
Column.Alignment := taLeftJustify;
Column.Width := 60;
Column := ListView1.Columns.Add;
Column.Caption := 'Artist';
Column.Alignment := taLeftJustify;
Column.Width := 200;
Column := ListView1.Columns.Add;
Column.Caption := 'Album';
Column.Alignment := taLeftJustify;
Column.Width := 200;
Column := ListView1.Columns.Add;
Column.Caption := 'Title';
Column.Alignment := taLeftJustify;
Column.Width := 200;
Column := ListView1.Columns.Add;
Column.Caption := 'File ALocation';
Column.Alignment := taLeftJustify;
Column.Width := 0;
end;
procedure AddFileToTree(ListView: TListView; FileName: String);
var
SR: TSearchRec;
ListItem: TListItem;
begin
// FileSize := 0;
if (FindFirst(FileName, faAnyFile, SR) = 0) then
begin
// FileSize := SR.Size;
// FileDate := FileDateToDateTime(SR.Time);
ListItem := ListView.Items.Add;
// get the MP3 File name
// Track Number
ListItem.Caption := ID3v2Tag.GetUnicodeText('TRCK'); //0
// get the Artist
ListItem.SubItems.Add(ID3v2Tag.GetUnicodeText('TPE1')); // 1
// get the Album
ListItem.SubItems.Add(ID3v2Tag.GetUnicodeText('TALB')); // 2
// get the Song title
ListItem.SubItems.Add(ID3v2Tag.GetUnicodeText('TIT2')); // 3
// get the path to the MP3 file
ListItem.SubItems.Add(FileName); // 4
// First we get the MP3 File name
ListItem.SubItems.Add(extractfilename(FileName)); //5
end;
end;
// This section was coded by: Remy Lebeau
// https://stackoverflow.com/a/78172902/2031172
procedure TForm1.ListView1SelectItem(Sender: TObject; Item: TListItem;
Selected: Boolean);
var
ls: TListItem;
sTrack, sArtist, sSong, sAlbum, sPath: string;
procedure CheckForMulti(var selectedStr: string; const value: string);
begin
if selectedStr = '' then
selectedStr := value
else if selectedStr <> value then
selectedStr := '<multi>';
end;
begin
ls := ListView1.Selected;
while Assigned(ls) do
begin
CheckForMulti(sTrack, ls.Caption);
CheckForMulti(sArtist, ls.SubItems[0]);
CheckForMulti(sSong, ls.SubItems[1]);
CheckForMulti(sAlbum, ls.SubItems[2]);
CheckForMulti(sPath, ls.SubItems[3]);
ls := ListView1.GetNextItem(ls, sdAll, [isSelected]);
end;
strTrack.Text := sTrack;
strArtist.Text := sArtist;
strTitle.Text := sSong;
strAlbum.Text := sAlbum;
strPath.Text := sPath;
end;
procedure TForm1.saveButtonClick(Sender: TObject);
var
ErrorCode, i: Integer;
LanguageID: TLanguageID;
FileName : string;
ListItem: TListItem;
getString : string;
LoadIt : integer;
begin
if ID3v2Tag.MajorVersion = 2 then begin
if MessageDlg('The tag in the file is an ID3v2.2 tag, if you click ''Yes'' it will be saved as an ID3v2.3 or ID3v2.4 tag. Do you want to save the tag?', mtConfirmation, [mbYes, mbCancel], 0) <> mrYes then begin
Exit;
end;
end;
ID3v2Tag.SetUnicodeText('TPE1', strArtist.Text);
ID3v2Tag.SetUnicodeText('TALB', strAlbum.Text);
ID3v2Tag.SetUnicodeText('TIT2', strTitle.Text);
ID3v2Tag.SetUnicodeText('TRCK', strTrack.Text);
ErrorCode := ID3v2Tag.SaveToFile(strPath.text);
// ErrorCode := ID3v2Tag.SaveToFile(strPath.Text{$IFDEF DEBUG}, False{$ENDIF});
if ErrorCode <> ID3V2LIBRARY_SUCCESS then begin
MessageDlg('Error saving ID3v2 tag, error code: ' + IntToStr(ErrorCode) + #13#10 + ID3v2TagErrorCode2String(ErrorCode), mtError, [mbOk], 0);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Item: TListItem;
test: System.String;
begin
memo1.Lines.Clear;
Item := ListView1.Selected;
while Item <> nil do
begin
// From Remy Lebeau - https://stackoverflow.com/a/14189378/2031172
Memo1.SelStart := Memo1.GetTextLen;
Memo1.SelLength := 0;
//memo1.lines.Add(Item.SubItems[3]);
// Added in this to created a comma delemited list.
// This should make it easier to iterate through.
Memo1.SelText := Item.SubItems[3] + ',';
Item := ListView1.GetNextItem(Item, sdAll, [isSelected]);
end;
// Remove the last character (comma) in the string.
// Mike Jablonski - https://stackoverflow.com/a/29102436/2031172
test := Memo1.Text;
test := Copy(test,1,length(test)-1);
Memo1.Text := test;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
Memo1.Clear;
end;
procedure TForm1.Button8Click(Sender: TObject);
var
i: integer;
LoadIt: integer;
begin
ListView1.Clear;
if OpenDialog1.execute then
for i := 0 to OpenDialog1.Files.Count - 1 do
if SameText(ExtractFileExt(OpenDialog1.Files[i]), '.mp3') then
begin
// Bug fix here. Changing from the original TEdit to the OpenDialog.Files[i] fixed song titles in list.
LoadIt := ID3v2Tag.LoadFromFile(OpenDialog1.Files[i]);
AddFileToTree(ListView1, OpenDialog1.Files[i]);
end;
end;
end.
LoadIt.dfm
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 375
ClientWidth = 688
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OnCreate = FormCreate
TextHeight = 13
object SidePanel: TPanel
Left = -4
Top = 128
Width = 189
Height = 252
TabOrder = 0
object Label1: TLabel
Left = 4
Top = 40
Width = 38
Height = 19
Caption = 'Artist'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -16
Font.Name = 'Tahoma'
Font.Style = []
ParentFont = False
end
object Label2: TLabel
Left = 4
Top = 95
Width = 31
Height = 19
Caption = 'Title'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -16
Font.Name = 'Tahoma'
Font.Style = []
ParentFont = False
end
object Label3: TLabel
Left = 4
Top = 68
Width = 47
Height = 19
Caption = 'Album'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -16
Font.Name = 'Tahoma'
Font.Style = []
ParentFont = False
end
object Label5: TLabel
Left = 4
Top = 120
Width = 56
Height = 19
Caption = 'Track #'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -16
Font.Name = 'Tahoma'
Font.Style = []
ParentFont = False
end
object strTitle: TEdit
Left = 61
Top = 93
Width = 121
Height = 21
TabOrder = 0
Text = 'Song Title'
end
object strArtist: TEdit
Left = 61
Top = 39
Width = 121
Height = 21
TabOrder = 1
Text = 'Artist Name'
end
object strAlbum: TEdit
Left = 61
Top = 66
Width = 121
Height = 21
TabOrder = 2
Text = 'Artist Name'
end
object strTrack: TEdit
Left = 61
Top = 120
Width = 121
Height = 21
TabOrder = 3
Text = 'Artist Name'
end
object saveButton: TButton
Left = 21
Top = 156
Width = 59
Height = 22
Caption = 'Save...'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
ParentFont = False
TabOrder = 4
OnClick = saveButtonClick
end
end
object MainPanel: TPanel
Left = 200
Top = 130
Width = 441
Height = 201
TabOrder = 1
object ListView1: TListView
Left = 104
Top = 27
Width = 200
Height = 150
Columns = <>
MultiSelect = True
RowSelect = True
SortType = stText
TabOrder = 0
ViewStyle = vsReport
OnSelectItem = ListView1SelectItem
end
end
object TopPanel: TPanel
Left = 8
Top = 8
Width = 649
Height = 114
TabOrder = 2
object Label4: TLabel
Left = 352
Top = 15
Width = 31
Height = 19
Caption = 'Path'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -16
Font.Name = 'Tahoma'
Font.Style = []
ParentFont = False
end
object SelectedLabel: TLabel
Left = 81
Top = 45
Width = 89
Height = 13
Caption = 'All Selected Paths.'
end
object Button8: TButton
Left = 9
Top = 12
Width = 59
Height = 22
Caption = 'Select...'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
ParentFont = False
TabOrder = 0
OnClick = Button8Click
end
object Edit1: TEdit
Left = 74
Top = 13
Width = 265
Height = 21
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
ParentFont = False
TabOrder = 1
end
object strPath: TEdit
Left = 389
Top = 12
Width = 244
Height = 21
TabOrder = 2
Text = 'strPath'
end
object Memo1: TMemo
Left = 74
Top = 64
Width = 505
Height = 41
ScrollBars = ssVertical
TabOrder = 3
end
object Button1: TButton
Left = 192
Top = 40
Width = 91
Height = 25
Caption = 'Get All Selected'
TabOrder = 4
OnClick = Button1Click
end
object Button2: TButton
Left = 308
Top = 40
Width = 75
Height = 25
Caption = 'Clear Paths'
TabOrder = 5
OnClick = Button2Click
end
end
object OpenDialog1: TOpenDialog
Filter = 'MP3|*.mp3'
Options = [ofHideReadOnly, ofAllowMultiSelect, ofEnableSizing]
Left = 598
Top = 324
end
end
Project1.dpr
program Project1;
uses
Forms,
LoadIt in 'LoadIt.pas' {Form1};
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
For what you are attempting, you need to keep track of the changes being made (ie, have a look at the
TEdit.Modifiedproperty) and then loop through the selected items saving those changes to each individual file as needed.Also,
AddFileToTree()is leaking theTSearchRecresources as it is not callingFindClose(). But, since you are not actually using theTSearchRecfor anything useful, you should just useFileExists()instead. Or better, just load the file unconditionally and then check whetherID3v2Tag.LoadFromFile()succeeded or failed.Try something more like this: