You've already forked lazarus-ccr
reading unicode tags and filenames, show/hide app window with single click tray icon, create album cover if not exists, several fixes when there is just one song in collection, artist tree icons, handling of track numbers in n[/m] format, show path of current file (in playlist and title list), log output was corrupt due the use of crt unit, etc. git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1761 8e941d3f-bd1b-0410-a28a-d453659cc2b4
1346 lines
37 KiB
ObjectPascal
1346 lines
37 KiB
ObjectPascal
{
|
|
Mediacollection Object for Cactus Jukebox
|
|
|
|
written by Sebastian Kraft, <c> 2006-2008
|
|
|
|
Contact the author at: sebastian_kraft@gmx.de
|
|
|
|
This Software is published under the GPL
|
|
|
|
|
|
|
|
|
|
}
|
|
Unit mediacol;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
Interface
|
|
|
|
Uses
|
|
Classes, SysUtils,
|
|
//Tagreader:
|
|
WMAfile, OggVorbis, FLACfile, mp3file, debug, LCLProc, lconvencoding, guesstag;
|
|
|
|
Type
|
|
// PMediaCollectionClass = ^TMediaCollectionClass;
|
|
TSrchType = ( FTrackSrch_Artist, FTrackSrch_ArtistAlbum, FAlbumSrch, FArtistSrch, FAllArtist );
|
|
TMediaType = (MTAudioFile, MTStream, MTCDAudio);
|
|
TPathFmt = ( FRelative, FDirect );
|
|
|
|
TMediaCollectionClass = Class;
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
{ TMediaFileClass }
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
TMediaFileClass = Class
|
|
Private
|
|
FTitle, FAlbum, FArtist: string;
|
|
FStreamUrl: string;
|
|
FMediaType: TMediaType;
|
|
|
|
function StrToUTF8(s:string): string;
|
|
Procedure read_tag_ogg;
|
|
Procedure read_tag_flac;
|
|
Procedure read_tag_wma;
|
|
Procedure read_tag_wave;
|
|
Procedure read_tag_mp3;
|
|
|
|
procedure write_tag_mp3;
|
|
|
|
Procedure SetArtist(aValue: String);
|
|
Procedure SetAlbum(aValue: String);
|
|
Procedure SetTitle(aValue: String);
|
|
Procedure setStreamUrl(aValue: String);
|
|
|
|
Public
|
|
Path: String;
|
|
CoverPath: ansistring;
|
|
Collection: TMediaCollectionClass;
|
|
Comment: ansistring;
|
|
GenreID: Byte;
|
|
Year: string[4];
|
|
Track: string[10]; // ####/####
|
|
Filetype: string[5];
|
|
Size: int64;
|
|
ID, Bitrate, Samplerate, Playlength, Action: longint;
|
|
Playtime: string;
|
|
index: integer;
|
|
|
|
constructor create(filepath:String; ParentCollection: TMediaCollectionClass);
|
|
constructor create(ParentCollection: TMediaCollectionClass);
|
|
destructor destroy;
|
|
Procedure Write_Tag;
|
|
Procedure Read_Tag;
|
|
Procedure assign(SourceObject: TMediaFileClass);
|
|
Function PathNameFromTag(var strFormat: string): Boolean;
|
|
Function PathNameFromTag_dryrun(var strFormat: string): string;
|
|
Function FullPathNameFromTag_dryrun(var strFormat: string): string;
|
|
Function move2path(strFilePath: string): Boolean;
|
|
Function LibraryPath(): string;
|
|
function GetCoverFile: string;
|
|
|
|
property Artist: string read FArtist write SetArtist;
|
|
property Album: string read FAlbum write SetAlbum;
|
|
property Title: string read FTitle write SetTitle;
|
|
property StreamUrl: string read FStreamUrl write SetStreamUrl;
|
|
property MediaType: TMediaType read FMEdiaType;
|
|
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
{ TMediaCollectionClass }
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
TMediaCollectionClass = Class(Tlist)
|
|
Private
|
|
FSorted, FEnumerated, FAutoEnum: Boolean;
|
|
FSrchAscending: Boolean;
|
|
FSrchPos: Integer;
|
|
FSrchArtist, FSrchAlbum: String;
|
|
FSrchType: TSrchType;
|
|
Function GetItems(index: integer): TMediaFileClass;
|
|
Procedure Recursive_AddDir(dir: String);
|
|
Procedure SetAutoEnum(Const AValue: boolean);
|
|
Procedure SetSorted(Const AValue: boolean);
|
|
Public
|
|
syncronize: Procedure (dir: String) Of object;
|
|
Savepath: string;
|
|
DirList: TStringList;
|
|
PathFmt: TPathFmt;
|
|
property Items[index: integer]: TMediaFileClass read GetItems;
|
|
property sorted: boolean read FSorted write SetSorted;
|
|
// when Sorted is set true, add/insert always adds at right position
|
|
// on changing state from false to true whole collection is getting sorted once
|
|
property AutoEnum: boolean read FAutoEnum write SetAutoEnum;
|
|
property enumerated: boolean read FEnumerated;
|
|
|
|
constructor create;
|
|
destructor destroy;
|
|
Procedure Assign(SourceCol:TMediaCollectionClass);
|
|
Function LoadFromFile(path: String): boolean;
|
|
Function SaveToFile(path: String): boolean;
|
|
Function SaveToFile: boolean;
|
|
Procedure clear;
|
|
Procedure insert(path: String; atInd: integer);
|
|
Function add(path: String): integer;
|
|
Function add(MedFileObj: TMediaFileClass): integer;
|
|
Procedure add_directory(dir: String);
|
|
Procedure remove(ind: integer);
|
|
Procedure move(dest, target: integer);
|
|
Function ItemCount: integer;
|
|
Procedure enumerate;
|
|
Procedure enumerate(StartFrom: integer);
|
|
|
|
Function getTracks(artist: String): integer;
|
|
Function getTracks(artist: String; StartFrom: integer): integer;
|
|
|
|
Function getTracks(artist, album: String): integer;
|
|
Function getTracks(artist, album: String; StartFrom: integer): integer;
|
|
|
|
Function getAlbums(artist: String): TStringList;
|
|
Function getAlbums(artist: String; StartFrom: integer): TStringList;
|
|
|
|
Function getNext: integer;
|
|
|
|
Function getArtists: integer;
|
|
Function getNextArtist: integer;
|
|
|
|
Function getIndexByPath(path: String): integer;
|
|
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Var MediaCollection, PlayerCol : TMediaCollectionClass;
|
|
|
|
implementation
|
|
|
|
Uses functions, config;
|
|
|
|
{$i cactus_const.inc}
|
|
|
|
|
|
{ TMediaCollectionClass }
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function TMediaCollectionClass.GetItems(index: integer): TMediaFileClass;
|
|
Begin
|
|
if (index>=0) and (index < Count) then
|
|
Result := (TMediaFileClass(Inherited Items [Index]));
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Procedure TMediaCollectionClass.Recursive_AddDir(dir: String);
|
|
|
|
Var mp3search,dirsearch: TSearchrec;
|
|
tmps: string;
|
|
fHandle: file Of byte;
|
|
Begin
|
|
dir := IncludeTrailingPathDelimiter(dir);
|
|
writeln('scanning through: '+dir);
|
|
syncronize(dir);
|
|
If FindFirst(dir+'*.*',faAnyFile,mp3search)=0 Then
|
|
Begin
|
|
Repeat
|
|
Begin
|
|
tmps := lowercase(ExtractFileExt(mp3search.name));
|
|
syncronize(dir);
|
|
If (tmps='.mp3') Or (tmps='.wav') Or (tmps='.ogg') Or (tmps='.wma')
|
|
Or (tmps='.flac') Or (tmps='.fla') Then
|
|
Begin
|
|
// Files with bad filenames may suddenly vanish from samba
|
|
// mounts when accessed. This will fiter them out.
|
|
system.assign(fHandle, dir+mp3search.name);
|
|
{$I-}
|
|
reset(fHandle);
|
|
close(fHandle);
|
|
{$I+}
|
|
if IOResult = 0
|
|
then
|
|
add(dir+mp3search.name);
|
|
End;
|
|
End;
|
|
Until FindNext(mp3search)<>0;
|
|
End;
|
|
Findclose(mp3search);
|
|
If Findfirst(dir+'*',faanyfile,dirsearch)=0 Then
|
|
Begin
|
|
syncronize(dir);
|
|
Repeat
|
|
Begin
|
|
If (dirsearch.attr And FaDirectory)=FaDirectory Then
|
|
Begin
|
|
If (dirsearch.name<>'..') And (dirsearch.name<>'.') Then
|
|
Recursive_AddDir(IncludeTrailingPathDelimiter(dir+dirsearch.name));
|
|
End;
|
|
End;
|
|
Until FindNext(dirsearch)<>0;
|
|
End;
|
|
Findclose(dirsearch);
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Procedure TMediaCollectionClass.SetAutoEnum(Const AValue: boolean);
|
|
Begin
|
|
FAutoEnum := AValue;
|
|
enumerate;
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Procedure TMediaCollectionClass.SetSorted(Const AValue: boolean);
|
|
Begin
|
|
Fsorted := AValue;
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
constructor TMediaCollectionClass.create;
|
|
Begin
|
|
Inherited create;
|
|
FSorted := true;
|
|
|
|
DirList := TStringList.Create;
|
|
PathFmt := FDirect;
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
destructor TMediaCollectionClass.destroy;
|
|
Begin
|
|
|
|
End;
|
|
|
|
Procedure TMediaCollectionClass.Assign(SourceCol: TMediaCollectionClass);
|
|
Begin
|
|
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function TMediaCollectionClass.LoadFromFile(path: String): boolean;
|
|
|
|
Var i: integer;
|
|
linecount: longint;
|
|
lfile: textfile;
|
|
RPath, tmps: String;
|
|
NumEntries: Integer;
|
|
MedFileObj: TMediaFileClass;
|
|
sortState: boolean;
|
|
tmpstring: string;
|
|
Begin
|
|
savepath := path;
|
|
sortState := FSorted;
|
|
linecount:=0;
|
|
|
|
system.assign(lfile,path);
|
|
{$i-}
|
|
reset(lfile);
|
|
{$i+}
|
|
if IoResult<>0 then begin
|
|
result := false;
|
|
writeln('unable to open file ', path);
|
|
exit;
|
|
end;
|
|
|
|
try
|
|
readln(lfile, tmps);
|
|
readln(lfile, tmps);
|
|
|
|
readln(lfile, tmps);
|
|
NumEntries := StrToInt(tmps);
|
|
writeln(NumEntries);
|
|
readln(lfile, tmps);
|
|
If tmps[length(tmps)]=';' Then System.Delete(tmps, length(tmps), 1);
|
|
i := pos(';', tmps);
|
|
While i<>0 Do
|
|
Begin
|
|
DirList.Add(IncludeTrailingPathDelimiter(copy(tmps, 1, i-1)));
|
|
system.delete(tmps, 1, i);
|
|
i := pos(';', tmps);
|
|
End;
|
|
DirList.Add(tmps);
|
|
If PathFmt = FRelative Then RPath := IncludeTrailingPathDelimiter(DirList[0])
|
|
Else RPath := '';
|
|
readln(lfile);
|
|
linecount:=5;
|
|
fsorted := false;
|
|
For i:= 0 To NumEntries-1 Do
|
|
Begin
|
|
MedFileObj := TMediaFileClass.create(self);
|
|
MedFileObj.action := ANOTHING;
|
|
readln(lfile, MedFileObj.path);
|
|
inc(linecount);
|
|
If PathFmt = FRelative Then MedFileObj.Path := RPath+MedFileObj.Path;
|
|
readln(lfile, MedFileObj.id);
|
|
inc(linecount);
|
|
readln(lfile, tmpstring);
|
|
MedFileObj.artist:=tmpstring;
|
|
inc(linecount);
|
|
readln(lfile, tmpstring);
|
|
MedFileObj.album:=tmpstring;
|
|
inc(linecount);
|
|
readln(lfile, tmpstring);
|
|
MedFileObj.title:=tmpstring;
|
|
inc(linecount);
|
|
readln(lfile, MedFileObj.year);
|
|
inc(linecount);
|
|
readln(lfile, MedFileObj.comment);
|
|
inc(linecount);
|
|
readln(lfile, MedFileObj.track);
|
|
inc(linecount);
|
|
readln(lfile, MedFileObj.size);
|
|
inc(linecount);
|
|
readln(lfile, MedFileObj.filetype);
|
|
inc(linecount);
|
|
readln(lfile, MedFileObj.bitrate);
|
|
inc(linecount);
|
|
readln(lfile, MedFileObj.samplerate);
|
|
inc(linecount);
|
|
readln(lfile, MedFileObj.playlength);
|
|
inc(linecount);
|
|
readln(lfile, MedFileObj.GenreID);
|
|
inc(linecount);
|
|
readln(lfile, MedFileObj.playtime);
|
|
inc(linecount);
|
|
add(MedFileObj);
|
|
End;
|
|
fsorted := sortState;
|
|
AutoEnum := true;
|
|
close(lfile);
|
|
writeln('library sucessfully loaded');
|
|
result := true;
|
|
Except
|
|
close(lfile);
|
|
fsorted := sortState;
|
|
writeln('lib seems corupted');
|
|
write('exception at entry ');
|
|
writeln(i);
|
|
write('line: ');writeln(linecount);
|
|
result := false;
|
|
End;
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function TMediaCollectionClass.SaveToFile(path: String): boolean;
|
|
|
|
Var lfile: textfile;
|
|
i: integer;
|
|
tmps: string;
|
|
Begin
|
|
savepath := path;
|
|
writeln('saving library to -> '+path);
|
|
Try
|
|
system.assign(lfile,path);
|
|
rewrite(lfile);
|
|
writeln(lfile,
|
|
'#####This config file is created by Cactus Jukebox. NEVER(!!) edit by hand!!!####')
|
|
;
|
|
writeln(lfile,'++++Config++++');
|
|
writeln(lfile, ItemCount);
|
|
For i:= 0 To DirList.Count-1 Do
|
|
tmps := tmps+DirList.Strings[i]+';';
|
|
writeln(lfile, tmps);
|
|
writeln(lfile,'++++Files++++');
|
|
tmps := '';
|
|
For i:= 0 To ItemCount-1 Do
|
|
Begin
|
|
If PathFmt = FDirect Then
|
|
tmps := items[i].Path
|
|
Else
|
|
Begin
|
|
tmps := copy(items[i].path, length(DirList[0]), length(items[i].path) - length(
|
|
DirList[0])+1);
|
|
If tmps[1]=DirectorySeparator Then system.Delete(tmps, 1, 1);
|
|
End;
|
|
//writeln(tmps);
|
|
writeln(lfile,tmps);
|
|
writeln(lfile,items[i].id);
|
|
writeln(lfile,items[i].artist);
|
|
writeln(lfile, items[i].album);
|
|
writeln(lfile, items[i].title);
|
|
writeln(lfile, items[i].year);
|
|
writeln(lfile, items[i].comment);
|
|
writeln(lfile, items[i].track);
|
|
writeln(lfile,items[i].size);
|
|
writeln(lfile,items[i].filetype);
|
|
writeln(lfile,items[i].bitrate);
|
|
writeln(lfile,items[i].samplerate);
|
|
writeln(lfile,items[i].playlength);
|
|
writeln(lfile,items[i].GenreID);
|
|
writeln(lfile,items[i].playtime);
|
|
End;
|
|
close(lfile);
|
|
write('written ');
|
|
write(i);
|
|
write(' of ');
|
|
writeln(ItemCount);
|
|
Except
|
|
writeln('error writing library to disk: check permissions!');
|
|
write('written ');
|
|
write(i);
|
|
write(' of ');
|
|
writeln(ItemCount);
|
|
End;
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function TMediaCollectionClass.SaveToFile: boolean;
|
|
Begin
|
|
result := SaveToFile(Savepath);
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Procedure TMediaCollectionClass.clear;
|
|
var AutoEnumStatus: boolean;
|
|
Begin
|
|
AutoEnumStatus:=AutoEnum;
|
|
AutoEnum:=false;
|
|
While count>0 Do
|
|
remove(0);
|
|
AutoEnum:=AutoEnumStatus;
|
|
DirList.Clear;
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Procedure TMediaCollectionClass.insert(path: String; atInd: integer);
|
|
|
|
Var i: integer;
|
|
Begin
|
|
inherited Insert(atInd, TMediaFileClass.create(path, self));
|
|
items[atInd].index := atInd;
|
|
items[atInd].Collection := self;
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function TMediaCollectionClass.add(path: String): integer;
|
|
|
|
Var i,z: integer;
|
|
MedFileObj: TMediaFileClass;
|
|
SortedState: boolean;
|
|
Begin
|
|
i := 0;
|
|
SortedState := FSorted;
|
|
FSorted := false;
|
|
MedFileObj := TMediaFileClass.create(path, self);
|
|
If (SortedState) Then
|
|
Begin
|
|
If (MedFileObj.Artist<>'') and (ItemCount>0) Then
|
|
Begin
|
|
While (i<ItemCount) And (CompareText(items[i].Artist, MedFileObj.Artist)<0)
|
|
Do
|
|
inc(i);
|
|
While (i<=ItemCount-1) And (CompareText(items[i].Artist, MedFileObj.Artist)=0) And
|
|
(CompareText(items[i].Title, MedFileObj.Title)<0)
|
|
Do
|
|
inc(i);
|
|
End
|
|
Else i := 0;
|
|
inherited Insert(i, MedFileObj);
|
|
If AutoEnum Then enumerate(i)
|
|
Else FEnumerated := false;
|
|
End
|
|
Else
|
|
Begin
|
|
i := Inherited Add(MedFileObj);
|
|
items[i].index := i;
|
|
End;
|
|
items[i].Collection := self;
|
|
result := i;
|
|
FSorted := SortedState;
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function TMediaCollectionClass.add(MedFileObj: TMediaFileClass): integer;
|
|
|
|
Var i: integer;
|
|
SortedState: boolean;
|
|
Begin
|
|
SortedState := FSorted;
|
|
FSorted := false;
|
|
i := 0;
|
|
If SortedState Then
|
|
Begin
|
|
try
|
|
If MedFileObj.Artist<>'' Then
|
|
Begin
|
|
While (i<ItemCount) And (CompareText(items[i].Artist, MedFileObj.Artist)<0)
|
|
Do
|
|
inc(i);
|
|
|
|
While (i<=ItemCount-1) And (CompareText(items[i].Artist, MedFileObj.Artist)=0) And
|
|
(CompareText(items[i].Title, MedFileObj.Title)<0)
|
|
Do
|
|
inc(i);
|
|
End;
|
|
inherited Insert(i, MedFileObj);
|
|
If AutoEnum Then enumerate(i)
|
|
Else FEnumerated := false;
|
|
|
|
except
|
|
writeln('exception sorting object in library');
|
|
writeln(MedFileObj.Path);
|
|
end;
|
|
End
|
|
Else
|
|
Begin
|
|
i := Inherited Add(MedFileObj);
|
|
items[i].index := i;
|
|
End;
|
|
items[i].Collection := self;
|
|
result := i;
|
|
FSorted := SortedState;
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Procedure TMediaCollectionClass.add_directory(dir: String);
|
|
Begin
|
|
DirList.Add(dir);
|
|
Recursive_AddDir(dir);
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Procedure TMediaCollectionClass.remove(ind: integer);
|
|
|
|
Var i: integer;
|
|
Begin
|
|
If (ind>=0) And (ind < Count) Then
|
|
Begin
|
|
Items[ind].free;
|
|
inherited Delete(ind);
|
|
dec(FSrchPos);
|
|
{ If (FSrchPos<=ind) Then dec(FSrchPos);
|
|
If (FSrchPos>ind) And (FSrchAscending) Then dec(FSrchPos);}
|
|
If AutoEnum Then enumerate(ind)
|
|
Else FEnumerated := false;
|
|
End;
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Procedure TMediaCollectionClass.move(dest, target: integer);
|
|
Begin
|
|
//TODO: Test move operation for all FsrchPos cases
|
|
inherited move(dest, target);
|
|
// if (FSrchPos>=dest) and (FSrchPos>target) then inc(FSrchPos);
|
|
If (FSrchPos>=dest) And (FSrchPos<target) Then dec(FSrchPos);
|
|
|
|
|
|
// if (FSrchPos>ind) and (FSrchAscending) then dec(FSrchPos);
|
|
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function TMediaCollectionClass.ItemCount: integer;
|
|
Begin
|
|
Result := Inherited Count;
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Procedure TMediaCollectionClass.enumerate;
|
|
Begin
|
|
enumerate(0);
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Procedure TMediaCollectionClass.enumerate(StartFrom: integer);
|
|
|
|
Var i: integer;
|
|
Begin
|
|
For i:=StartFrom To ItemCount-1 Do
|
|
items[i].index := i;
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function TMediaCollectionClass.GetTracks(artist: String): integer;
|
|
Begin
|
|
result := getTracks(artist, 0);
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function TMediaCollectionClass.getTracks(artist, album: String): integer;
|
|
Begin
|
|
result := getTracks(artist, album, 0);
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function TMediaCollectionClass.GetTracks(artist: String; StartFrom: integer): integer;
|
|
|
|
Var i: integer;
|
|
Begin
|
|
FSrchType := FTrackSrch_Artist;
|
|
|
|
artist := lowercase(artist);
|
|
FSrchArtist := artist;
|
|
If StartFrom<>0 Then
|
|
Begin
|
|
If (sorted=false) Then
|
|
StartFrom := 0
|
|
Else
|
|
Begin
|
|
i := AnsiCompareText(Items[StartFrom].Artist, artist);
|
|
If (i=0) Or (i>0) Then FSrchAscending := true
|
|
Else FSrchAscending := false;
|
|
End;
|
|
End;
|
|
|
|
i := StartFrom;
|
|
If (i<>0) And (FSrchAscending) Then
|
|
Begin
|
|
While (lowercase(Items[i].Artist)<>artist) And (i>=0) Do
|
|
dec(i);
|
|
While (lowercase(Items[i].Artist)=artist) And (i>0) Do
|
|
dec(i);
|
|
inc(i);
|
|
FSrchPos := i;
|
|
End
|
|
Else
|
|
Begin
|
|
While (i<Count) And (lowercase(Items[i].Artist)<>artist) Do
|
|
inc(i);
|
|
If i<>Count Then FSrchPos := i
|
|
Else FSrchPos := -1;
|
|
End;
|
|
|
|
Result := FSrchPos;
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function TMediaCollectionClass.getTracks(artist, album: String;
|
|
StartFrom: integer): integer;
|
|
|
|
Var i: integer;
|
|
Begin
|
|
album:=LowerCase(album);
|
|
artist:=LowerCase(artist);
|
|
FSrchArtist := artist;
|
|
FSrchAlbum := album;
|
|
i := getTracks(artist, StartFrom);
|
|
FSrchType := FTrackSrch_ArtistAlbum;
|
|
While lowercase(items[i].Album)<>album Do
|
|
inc(i);
|
|
|
|
FSrchPos := i;
|
|
Result := i;
|
|
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function TMediaCollectionClass.getAlbums(artist: String): TStringList;
|
|
Begin
|
|
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function TMediaCollectionClass.getAlbums(artist: String; StartFrom: integer
|
|
): TStringList;
|
|
|
|
Var tmplist : TStringList;
|
|
i: integer;
|
|
Begin
|
|
artist := lowercase(artist);
|
|
If StartFrom<>0 Then
|
|
Begin
|
|
If (sorted=false) Then
|
|
StartFrom := 0
|
|
Else
|
|
Begin
|
|
i := AnsiCompareText(Items[StartFrom].Artist, artist);
|
|
If (i=0) Or (i>0) Then FSrchAscending := true
|
|
Else FSrchAscending := false;
|
|
End;
|
|
End;
|
|
|
|
i := StartFrom;
|
|
If (i<>0) And (FSrchAscending) Then
|
|
Begin
|
|
While (lowercase(Items[i].Artist)<>artist) And (i>=0) Do
|
|
dec(i);
|
|
While (lowercase(Items[i].Artist)=artist) And (i>0) Do
|
|
dec(i);
|
|
inc(i);
|
|
End
|
|
Else
|
|
Begin
|
|
While (i<count) And (lowercase(Items[i].Artist)<>artist) Do
|
|
inc(i);
|
|
If i=Count Then i := -1;
|
|
End;
|
|
tmplist := TStringList.Create;
|
|
tmplist.Sorted := true;
|
|
tmplist.CaseSensitive := false;
|
|
tmplist.Duplicates := dupIgnore;
|
|
If (i>=0) And (i<Count) Then
|
|
Begin
|
|
|
|
While (i<Count) And (lowercase(Items[i].Artist)=artist) Do
|
|
Begin
|
|
If Items[i].Album<>'' Then tmplist.AddObject(items[i].Album, Items[i])
|
|
Else tmplist.AddObject('Unknown', Items[i]);
|
|
inc(i);
|
|
End;
|
|
Result := tmplist;
|
|
End;
|
|
|
|
End;
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function TMediaCollectionClass.getArtists: integer;
|
|
Begin
|
|
FSrchPos := 0;
|
|
FSrchArtist := lowercase(Items[0].Artist);
|
|
result := FSrchPos;
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function TMediaCollectionClass.getNextArtist: integer;
|
|
|
|
Var i: integer;
|
|
Begin
|
|
i := FSrchPos;
|
|
Repeat
|
|
inc(i)
|
|
Until (i>=Count) Or (lowercase(items[i].Artist)<>FSrchArtist);
|
|
If i<Count Then
|
|
Begin
|
|
FSrchArtist := lowercase(Items[i].Artist);
|
|
FSrchPos := i;
|
|
Result := i;
|
|
End
|
|
Else result := -1;
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function TMediaCollectionClass.GetNext: integer;
|
|
|
|
Var i: integer;
|
|
Begin
|
|
Case FSrchType Of
|
|
FTrackSrch_Artist:
|
|
Begin
|
|
Repeat
|
|
inc(FSrchPos)
|
|
Until (FSrchPos>=ItemCount) Or (lowercase(Items[FSrchPos].Artist)=
|
|
FSrchArtist);
|
|
If (FSrchPos<>ItemCount) And (lowercase(Items[FSrchPos].Artist)=
|
|
FSrchArtist)Then
|
|
result := FSrchPos
|
|
Else
|
|
result := -1;
|
|
exit;
|
|
End;
|
|
FTrackSrch_ArtistAlbum:
|
|
Begin
|
|
Repeat
|
|
inc(FSrchPos)
|
|
Until (FSrchPos>=ItemCount) Or ((lowercase(Items[FSrchPos].Album)=
|
|
FSrchAlbum) And (lowercase(Items[FSrchPos].Artist)=
|
|
FSrchArtist));
|
|
If (FSrchPos<>ItemCount) And ((lowercase(Items[FSrchPos].Album)=
|
|
FSrchAlbum) And (lowercase(Items[FSrchPos].Artist)=FSrchArtist)
|
|
) Then
|
|
result := FSrchPos
|
|
Else
|
|
result := -1;
|
|
exit;
|
|
End;
|
|
End;
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function TMediaCollectionClass.GetIndexByPath(path: String): integer;
|
|
|
|
Var i: integer;
|
|
Begin
|
|
i := ItemCount;
|
|
Repeat
|
|
dec(i)
|
|
Until (i<0) Or (items[i].Path=path);
|
|
result := i;
|
|
End;
|
|
|
|
function TMediaFileClass.StrToUTF8(s: string): string;
|
|
var
|
|
w: Word;
|
|
begin
|
|
if length(s)>2 then begin
|
|
W := PWord(@S[1])^;
|
|
if (W=$FFFE) or (W=$FEFF) then begin
|
|
s := copy(s, 3, length(s)-2);
|
|
if (W=$FFFE) then
|
|
result := UCS2BEToUTF8(s)
|
|
else
|
|
result := UCS2LEToUTF8(s);
|
|
exit;
|
|
end
|
|
end;
|
|
if FindInvalidUTF8Character(pchar(s), Length(s), false)>=0 then
|
|
result := ISO_8859_1ToUTF8(s)
|
|
else
|
|
result := S;
|
|
end;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
{ TMediaFileClass }
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ogg-Support changed by monta
|
|
Procedure TMediaFileClass.read_tag_ogg;
|
|
Var OGGFile: TOggVorbis;
|
|
Begin
|
|
OGGFile := TOggVorbis.Create;
|
|
try
|
|
if FileExists(Path) then
|
|
begin
|
|
writeln(path);
|
|
OGGFile.ReadFromFile(Path);
|
|
artist := UTF8Encode(OGGFile.Artist);
|
|
title := UTF8Encode(OGGFile.Title);
|
|
album := UTF8Encode(OGGFile.Album);
|
|
Bitrate := OGGFile.BitRate;
|
|
Year := OGGFile.Date;
|
|
Samplerate := OGGFile.SampleRate;
|
|
Comment := OGGFile.Comment;
|
|
Track := IntToStr(OGGFile.Track);
|
|
Playlength := round(OGGFile.Duration);
|
|
Playtime := SecondsToFmtStr(Playlength);
|
|
GenreID := StrToIntDef(OGGFile.Genre, 0);
|
|
end;
|
|
finally
|
|
OGGFile.Free;
|
|
end;
|
|
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// flac-Support added by monta
|
|
Procedure TMediaFileClass.read_tag_flac;
|
|
Var FLACFile: TFLACfile;
|
|
Begin
|
|
FLACfile := TFLACfile.Create;
|
|
try
|
|
if FileExists(Path) then
|
|
begin
|
|
FLACFile.ReadFromFile(Path);
|
|
artist := UTF8Encode(FLACFile.Artist);
|
|
title := UTF8Encode(FLACFile.Title);
|
|
album := UTF8Encode(FLACFile.Album);
|
|
Bitrate := FLACFile.BitRate;
|
|
Year := FLACFile.Year;
|
|
Samplerate := FLACFile.SampleRate;
|
|
Comment := FLACFile.Comment;
|
|
Track := FLACFile.TrackString;
|
|
Playlength := round(FLACFile.Duration);
|
|
Playtime := SecondsToFmtStr(Playlength);
|
|
GenreID := StrToIntDef(FLACFile.Genre, 0);
|
|
end;
|
|
finally
|
|
FLACFile.Free;
|
|
end;
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// wma-Support added by monta
|
|
Procedure TMediaFileClass.read_tag_wma;
|
|
Var WMAFile: TWMAfile;
|
|
Begin
|
|
WMAFile := TWMAfile.Create;
|
|
try
|
|
if FileExists(Path) then
|
|
begin
|
|
WMAFile.ReadFromFile(Path);
|
|
artist := UTF8Encode(WMAFile.Artist);
|
|
title := UTF8Encode(WMAFile.Title);
|
|
album := UTF8Encode(WMAFile.Album);
|
|
Bitrate := WMAFile.BitRate;
|
|
Year := WMAFile.Year;
|
|
Samplerate := WMAFile.SampleRate;
|
|
Comment := WMAFile.Comment;
|
|
Track := IntToStr(WMAFile.Track);
|
|
Playlength := round(WMAFile.Duration);
|
|
Playtime := SecondsToFmtStr(Playlength);
|
|
GenreID := StrToIntDef(WMAFile.Genre, 0);
|
|
end;
|
|
finally
|
|
WMAFile.Free;
|
|
end;
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Procedure TMediaFileClass.read_tag_wave;
|
|
|
|
Var li: cardinal;
|
|
b: byte;
|
|
z: integer;
|
|
mp3filehandle: longint;
|
|
tmps: string;
|
|
Begin
|
|
Try
|
|
mp3filehandle := fileopen(path, fmOpenRead);
|
|
fileseek(mp3filehandle,8,fsfrombeginning);
|
|
b := 0;
|
|
Repeat
|
|
Begin
|
|
inc(b);
|
|
fileread(mp3filehandle,li,4);
|
|
End;
|
|
Until (li=$20746D66) Or (b=15);
|
|
fileread(mp3filehandle,li,4);
|
|
fileread(mp3filehandle,li,4);
|
|
fileread(mp3filehandle,li,4);
|
|
samplerate := li;
|
|
fileread(mp3filehandle,li,4);
|
|
bitrate := (li Div 1024)*8;
|
|
playlength := size Div li;
|
|
|
|
playtime := SecondsToFmtStr(Playlength);
|
|
Except
|
|
writeln('**EXCEPTION reading wave file '+path+'**');
|
|
End;
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
procedure TMediaFileClass.read_tag_mp3;
|
|
Var MP3File: TMP3File;
|
|
Begin
|
|
MP3File := TMP3File.Create;
|
|
try
|
|
if FileExists(Path) then
|
|
begin
|
|
// writeln(path);
|
|
MP3File.ReadTag(Path);
|
|
artist := StrToUTF8(MP3File.Artist);
|
|
title := StrToUTF8(MP3File.Title);
|
|
album := StrToUTF8(MP3File.Album);
|
|
Bitrate := MP3File.BitRate;
|
|
Year := StrToUTF8(MP3File.Year);
|
|
Samplerate := MP3File.SampleRate;
|
|
Comment := StrToUTF8(MP3File.Comment);
|
|
Track := StrToUTF8(MP3File.Track);
|
|
Playlength := round(MP3File.Playlength);
|
|
Playtime := SecondsToFmtStr(Playlength);
|
|
GenreID := (MP3File.GenreID);
|
|
end;
|
|
finally
|
|
MP3File.Free;
|
|
end;
|
|
end;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
procedure TMediaFileClass.write_tag_mp3;
|
|
var MP3File: TMP3File;
|
|
begin
|
|
MP3File:=TMP3File.create;
|
|
|
|
MP3File.Artist:=UTF8ToISO_8859_1(FArtist);
|
|
MP3File.Album:=UTF8ToISO_8859_1(FAlbum);
|
|
MP3File.Title:=UTF8ToISO_8859_1(FTitle);
|
|
MP3File.Track:= Track;
|
|
MP3File.Comment:=UTF8ToISO_8859_1(Comment);
|
|
MP3File.Year:= Year;
|
|
MP3File.GenreID:=(GenreID);
|
|
|
|
MP3File.WriteTag(Path);
|
|
|
|
MP3File.Free;
|
|
|
|
end;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Procedure TMediaFileClass.Read_Tag;
|
|
var TagFromName: TTagFromFilename;
|
|
Begin
|
|
If filetype='.wav' Then read_tag_wave;
|
|
If filetype='.ogg' Then read_tag_ogg;
|
|
If filetype='.mp3' Then read_tag_mp3;
|
|
If filetype='.wma' Then read_tag_wma;
|
|
If (filetype='.flac') or (filetype='.fla') Then read_tag_flac;
|
|
|
|
if (Artist='') and CactusConfig.GuessTag then begin
|
|
TagFromName:=TTagFromFilename.create;
|
|
TagFromName.ReadTag(Path);
|
|
if TagFromName.Artist<>'' then Artist:=TagFromName.Artist+'*';
|
|
if (Title='') and (TagFromName.Artist<>'') then Title:=TagFromName.Title+'*';
|
|
if (Track='') and (TagFromName.Track<>'') then Track:=TagFromName.Track+'*';
|
|
TagFromName.Free;
|
|
end;
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Procedure TMediaFileClass.SetArtist(aValue: String);
|
|
|
|
Var i, start: integer;
|
|
Begin
|
|
i := index;
|
|
start := index;
|
|
FArtist := aValue;
|
|
If (Collection<>nil) and Collection.sorted Then
|
|
Begin
|
|
If (i<Collection.Count-1) And (CompareText(FArtist, Collection.Items[i+1].Artist)>0) Then
|
|
Begin
|
|
inc(i);
|
|
While (i<=Collection.Count-1) And (compareText(FArtist, Collection.Items[i].Artist)>0)
|
|
Do
|
|
Begin
|
|
inc(i);
|
|
End;
|
|
While (i<=Collection.Count-1) And (compareText(FTitle, Collection.Items[i].Title)>0)
|
|
And (CompareText(FArtist, Collection.Items[i].Artist)=0) Do
|
|
Begin
|
|
inc(i);
|
|
End;
|
|
Collection.Move(index, i-1);
|
|
If Collection.AutoEnum Then Collection.enumerate(start);
|
|
End;
|
|
If (i>0) And (CompareText(FArtist, Collection.Items[i-1].Artist)<0) Then
|
|
Begin
|
|
dec(i);
|
|
While (i>=0) And (compareText(FArtist, Collection.Items[i].Artist)<0) Do
|
|
Begin
|
|
dec(i);
|
|
End;
|
|
|
|
While ((i>=0) And (compareText(FTitle, Collection.Items[i].Title)<0))
|
|
And (CompareText(FArtist, Collection.Items[i].Artist)=0) Do
|
|
Begin
|
|
dec(i);
|
|
End;
|
|
Collection.Move(index, i+1);
|
|
If Collection.AutoEnum Then Collection.enumerate;
|
|
End;
|
|
End;
|
|
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Procedure TMediaFileClass.SetAlbum(aValue: String);
|
|
Begin
|
|
FAlbum := aValue;
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Procedure TMediaFileClass.SetTitle(aValue: String);
|
|
|
|
Var i, start: integer;
|
|
Begin
|
|
FTitle := aValue;
|
|
i := index;
|
|
start := index;
|
|
If (Collection<>nil) and Collection.sorted Then
|
|
Begin
|
|
writeln(i);
|
|
If (i<Collection.Count-1) And (CompareText(FTitle, Collection.Items[i+1].Title)>0)
|
|
And (CompareText(FArtist, Collection.Items[i+1].Artist)=0) Then
|
|
Begin
|
|
inc(i);
|
|
While ((i<=Collection.Count-1) And (compareText(FTitle, Collection.Items[i].Title)>0))
|
|
And (CompareText(FArtist, Collection.Items[i].Artist)=0) Do
|
|
Begin
|
|
inc(i);
|
|
End;
|
|
Collection.Move(index, i-1);
|
|
If Collection.AutoEnum Then Collection.enumerate(start);
|
|
End;
|
|
|
|
If (i>0) And (CompareText(FTitle, Collection.Items[i-1].Title)<0)
|
|
And (CompareText(FArtist, Collection.Items[i-1].Artist)=0) Then
|
|
Begin
|
|
dec(i);
|
|
While ((i>=0) And (compareText(FTitle, Collection.Items[i].Title)<0))
|
|
And (compareText(FArtist, Collection.Items[i].Artist)=0) Do
|
|
Begin
|
|
dec(i);
|
|
End;
|
|
Collection.Move(index, i+1);
|
|
If Collection.AutoEnum Then Collection.enumerate;
|
|
End;
|
|
End;
|
|
|
|
End;
|
|
|
|
Procedure TMediaFileClass.setStreamUrl(aValue: String);
|
|
Begin
|
|
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
constructor TMediaFileClass.create(filepath: String; ParentCollection: TMediaCollectionClass);
|
|
|
|
Var tmpfile: file Of byte;
|
|
Begin
|
|
Collection := ParentCollection;
|
|
path := filepath;
|
|
action := ANOTHING;
|
|
If pos(URLID, filepath)=0 Then FMediaType := MTStream
|
|
Else FMediaType := MTAudioFile;
|
|
Filemode := 0;
|
|
try
|
|
system.assign(tmpfile, path);
|
|
//Open file temporaly to get some information about it
|
|
reset(tmpfile);
|
|
size := filesize(tmpfile);
|
|
//get filesize
|
|
ID := crc32(path);
|
|
// calc unique file ID
|
|
filetype := lowercase(ExtractFileExt(filepath));
|
|
close(tmpfile);
|
|
except debugoutln('ERROR reading file '+filepath,2);
|
|
end;
|
|
Filemode := 2;
|
|
read_tag;
|
|
//finally read tag information
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
constructor TMediaFileClass.create(ParentCollection: TMediaCollectionClass);
|
|
Begin
|
|
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
destructor TMediaFileClass.destroy;
|
|
Begin
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Procedure TMediaFileClass.Write_Tag;
|
|
begin
|
|
if Filetype='.mp3' then write_tag_mp3;
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Procedure TMediaFileClass.assign(SourceObject: TMediaFileClass);
|
|
Begin
|
|
|
|
End;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function TMediaFileClass.move2path(strFilePath: string): Boolean;
|
|
var
|
|
i: integer;
|
|
strSrc, strDest, strTmp: string;
|
|
begin
|
|
// did the filename change at all?
|
|
strSrc := Path;
|
|
strDest := strFilePath;
|
|
if strSrc = strDest then
|
|
begin
|
|
Result := true;
|
|
exit;
|
|
end;
|
|
|
|
// has the folder changed?
|
|
strSrc := ExtractFilePath(Path);
|
|
strDest := ExtractFilePath(strFilePath);
|
|
if strSrc <> strDest then
|
|
if NOT DirectoryExists(strDest) then
|
|
ForceDirectories(strDest);
|
|
|
|
// does the target file alredy existe?
|
|
strDest := strFilePath;
|
|
if FileExists(strDest) then
|
|
begin
|
|
while strDest[Length(strDest)-1] <> '.' do
|
|
strDest := Copy(strDest, 1, Length(strDest)-1);
|
|
strDest := Copy(strDest, 1, Length(strDest)-2);
|
|
i := 2;
|
|
repeat
|
|
begin
|
|
strTmp := '(' + IntToStr(i) + ')' + Filetype;
|
|
i += 1;
|
|
end
|
|
until NOT FileExists(strDest + strTmp)
|
|
end;
|
|
strDest += strTmp;
|
|
|
|
// move the file
|
|
strSrc := Path;
|
|
RenameFile(strSrc, strDest);
|
|
|
|
// remove old folder and folders above if empty
|
|
strSrc := ExtractFilePath(Path);
|
|
while DirectoryIsEmpty(strSrc) do
|
|
begin
|
|
RemoveDir(strSrc);
|
|
i := LastDelimiter(PathDelim,ExcludeTrailingPathDelimiter(strSrc));
|
|
Delete(strSrc, i, Length(strSrc)-i+1);
|
|
end;
|
|
|
|
result := true; // FIXME write error detection needed
|
|
|
|
if result then
|
|
Path := strDest;
|
|
end;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function TMediaFileClass.PathNameFromTag_dryrun(var strFormat: string): string;
|
|
var
|
|
strArtist, strAlbum, strTitle, strTrack, strYear: string;
|
|
strLeft, strRight, strMid: string;
|
|
chrLetter: char;
|
|
intPos, intPos2: integer;
|
|
bNonEmpty: Boolean;
|
|
begin
|
|
// format string could be '%a/%a - %b - %n - %t'
|
|
|
|
// if existant, replace unwanted chars in tags
|
|
strArtist := MakeValidFilename(Artist);
|
|
strAlbum := MakeValidFilename(Album);
|
|
strTitle := MakeValidFilename(Title);
|
|
strTrack := MakeValidFilename(Track);
|
|
strYear := MakeValidFilename(Year);
|
|
|
|
|
|
result := strFormat;
|
|
// result := '%a/%a - %b%? - ?%n - %t%? in ?%y';
|
|
|
|
while (Pos('%?', result) >0) and (Pos('?%', result) >0) do
|
|
begin
|
|
intPos := Pos('%?', result);
|
|
intPos2 := Pos('?%', result);
|
|
if length(result) < intPos2+2 then break;
|
|
if intPos2 < intPos then break; // FIXME could be more elegant
|
|
|
|
strLeft := Copy(result, 1, intPos -1);
|
|
strRight := Copy(result, intPos2 +3, Length(result) - intPos2 +3);
|
|
strMid := Copy (result, intPos +2, Length(result) - intPos -1 -(Length(result) - intPos2) -1);
|
|
chrLetter := result[intPos2 +2];
|
|
|
|
bNonEmpty := false;
|
|
case chrLetter of
|
|
'a': if strArtist <> '' then bNonEmpty := true;
|
|
'b': if strAlbum <> '' then bNonEmpty := true;
|
|
't': if strTitle <> '' then bNonEmpty := true;
|
|
'n': if strTrack <> '' then bNonEmpty := true;
|
|
'y': if strYear <> '' then bNonEmpty := true;
|
|
end;
|
|
|
|
if bNonEmpty then
|
|
result := strLeft + strMid + '%' + chrLetter + strRight
|
|
else
|
|
result := strLeft + strRight;
|
|
end;
|
|
|
|
result := StringReplace(result, '%a', strArtist, [rfReplaceAll, rfIgnoreCase]);
|
|
result := StringReplace(result, '%b', strAlbum, [rfReplaceAll, rfIgnoreCase]);
|
|
result := StringReplace(result, '%t', strTitle, [rfReplaceAll, rfIgnoreCase]);
|
|
result := StringReplace(result, '%n', strTrack, [rfReplaceAll, rfIgnoreCase]);
|
|
result := StringReplace(result, '%y', strYear, [rfReplaceAll, rfIgnoreCase]);
|
|
result += FileType;
|
|
end;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function TMediaFileClass.FullPathNameFromTag_dryrun(var strFormat: string): string;
|
|
begin
|
|
result := LibraryPath() + PathNameFromTag_dryrun(strFormat);
|
|
end;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function TMediaFileClass.PathNameFromTag(var strFormat: string): Boolean;
|
|
begin
|
|
result := move2path(FullPathNameFromTag_dryrun(strFormat));
|
|
end;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function TMediaFileClass.LibraryPath(): string;
|
|
var
|
|
i: integer;
|
|
begin
|
|
result := '';
|
|
For i:= 0 To MediaCollection.dirlist.Count-1 Do
|
|
if Pos(Collection.dirlist[i], Path) > 0 then
|
|
begin
|
|
result := IncludeTrailingPathDelimiter(Collection.dirlist[i]);
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
function TMediaFileClass.GetCoverFile: string;
|
|
begin
|
|
result := Artist+'_'+album+'.jpeg'
|
|
end;
|
|
|
|
|
|
End.
|