source: trunk/UPlaylist.pas

Last change on this file was 9, checked in by chronos, 2 years ago
  • Modified: Split search and generation phase.
File size: 5.2 KB
Line 
1unit UPlaylist;
2
3{$mode Delphi}
4
5interface
6
7uses
8 Classes, SysUtils, Generics.Collections;
9
10type
11 TPlaylistItem = class
12 Time: TDateTime;
13 Title: string;
14 RemoteName: string;
15 LocationOriginal: string;
16 Location: string;
17 Creator: string;
18 TrackNum: string;
19 Album: string;
20 end;
21
22 { TPlaylistItems }
23
24 TPlaylistItems = class(TObjectList<TPlayListItem>)
25 function AddNew: TPlaylistItem;
26 end;
27
28 { TPlaylist }
29
30 TPlaylist = class
31 public
32 Items: TPlaylistItems;
33 SearchBaseDir: string;
34 RemoteBaseDir: string;
35 FilteredFileExtensions: array of string;
36 procedure Search;
37 procedure GenerateM3U;
38 procedure GenerateXSPF;
39 constructor Create;
40 destructor Destroy; override;
41 end;
42
43
44implementation
45
46resourcestring
47 SFileNotFound = 'File ''%s'' not found.';
48
49function InStrArray(Value: string; StrArray: array of string): Boolean;
50var
51 I: Integer;
52begin
53 I := 0;
54 while (I < Length(StrArray)) and (StrArray[I] <> Value) do Inc(I);
55 if I < Length(StrArray) then Result := True
56 else Result := False;
57end;
58
59procedure FileSearch(Files: TStringList; const PathName: string; ExtList: array of string);
60var
61 Rec: TSearchRec;
62 Path: string;
63begin
64 Path := IncludeTrailingPathDelimiter(PathName);
65 if FindFirst(Path + '*', faAnyFile, Rec) = 0 then
66 try
67 repeat
68 if Rec.Name = '..' then continue
69 else if Rec.Name = '.' then continue
70 else if (Rec.Attr and faDirectory) > 0 then FileSearch(Files, Path + Rec.Name, ExtList)
71 else if InStrArray(LowerCase(ExtractFileExt(Rec.Name)), ExtList) then begin
72 Files.Add(Path + Rec.Name);
73 end;
74 until FindNext(Rec) <> 0;
75 finally
76 FindClose(Rec);
77 end;
78end;
79
80function FileDate(FileName: string): TDateTime;
81var
82 fa: LongInt;
83begin
84 fa := FileAge(FileName);
85 if Fa <> -1 then begin
86 Result := FileDateToDateTime(fa);
87 end else
88 raise Exception.Create(Format(SFileNotFound, [FileName]));
89end;
90
91
92{ TPlaylistItems }
93
94function TPlaylistItems.AddNew: TPlaylistItem;
95begin
96 Result := TPlaylistItem.Create;
97 Add(Result);
98end;
99
100procedure TPlaylist.Search;
101var
102 Files: TStringList;
103 I: Integer;
104 PlaylistItem: TPlaylistItem;
105 NameRemoved: Boolean;
106 Part: string;
107 OutInt: Integer;
108begin
109 Files := TStringList.Create;
110 try
111 FileSearch(Files, SearchBaseDir, FilteredFileExtensions);
112 for I := 0 to Files.Count - 1 do begin
113 PlaylistItem := Items.AddNew;
114 with PlayListItem do begin
115 RemoteName := RemoteBaseDir + Copy(Files[I], Length(ParamStr(1)) + 2, High(Integer));
116 LocationOriginal := StringReplace(RemoteName, '&', '&amp;', [rfReplaceAll]);
117 Location := StringReplace(LocationOriginal, '_', ' ', [rfReplaceAll]);
118 Album := ExtractFileName(ExtractFileDir(Location));
119 NameRemoved := False;
120
121 // Detect Creator from directory name
122 if Pos(' - ', Album) > 0 then begin
123 Creator := Copy(Album, 1, Pos(' - ', Album) - 1);
124 Delete(Album, 1, Length(Creator) + 3);
125 end else Creator := Album;
126 Title := Copy(ExtractFileName(Location), 1, Length(ExtractFileName(Location)) - Length(ExtractFileExt(Location)));
127
128 // Remove starting with album name from title
129 Part := Creator + ' - ';
130 if Copy(Title, 1, Length(Part)) = Part then begin
131 Delete(Title, 1, Length(Part));
132 NameRemoved := True;
133 end;
134
135 // Try to load Creator from name
136 if (Pos(' - ', Title) > 0) and (not NameRemoved) then begin
137 Part := Copy(Title, 1, Pos(' - ', Title) - 1);
138 // Avoid track number which can be first title part
139 if not TryStrToInt(Part, OutInt) then begin
140 Creator := Part;
141 Delete(Title, 1, Length(Creator) + 3);
142 end;
143 end;
144 // Detect track number from title
145 if Pos(' - ', Title) > 0 then begin
146 TrackNum := Copy(Title, 1, Pos(' - ', Title) - 1);
147 if TryStrToInt(TrackNum, OutInt) then
148 Delete(Title, 1, Length(TrackNum) + 3)
149 else TrackNum := '';
150 end else TrackNum := '';
151
152 Time := FileDate(Files[I]);
153 end;
154 end;
155 finally
156 Files.Free;
157 end;
158end;
159
160procedure TPlaylist.GenerateM3U;
161var
162 I: Integer;
163begin
164 WriteLn('#EXTM3U');
165 for I := 0 to Items.Count - 1 do
166 with Items[I] do begin
167 WriteLn(LocationOriginal);
168 end;
169end;
170
171procedure TPlaylist.GenerateXSPF;
172var
173 I: Integer;
174begin
175 WriteLn('<?xml version="1.0" encoding="UTF-8"?>');
176 WriteLn('<playlist version="1" xmlns="http://xspf.org/ns/0/">');
177 WriteLn('<trackList>');
178 for I := 0 to Items.Count - 1 do
179 with Items[I] do begin
180 WriteLn('<track>');
181 WriteLn('<title>' + Title + '</title>');
182 WriteLn('<location>' + LocationOriginal + '</location>');
183 WriteLn('<album>' + Album + '</album>');
184 WriteLn('<creator>' + Creator + '</creator>');
185 WriteLn('<trackNum>' + TrackNum + '</trackNum>');
186 WriteLn('<annotation>' + FormatDateTime('yyyy-mm-dd', Time) + '</annotation>');
187 WriteLn('</track>');
188 end;
189 WriteLn('</trackList>');
190 WriteLn('</playlist>');
191end;
192
193constructor TPlaylist.Create;
194begin
195 FilteredFileExtensions := ['.mp3', '.ac3', '.flac', '.it', '.m4a', '.wma', '.s3m', '.ogg'];
196 Items := TPlaylistItems.Create;
197end;
198
199destructor TPlaylist.Destroy;
200begin
201 FreeAndNil(Items);
202 inherited;
203end;
204
205
206end.
207
Note: See TracBrowser for help on using the repository browser.