unit UPlaylist; interface type TPlaylistItem = record Artist: String; Title: String; SongID: Integer; end; APlaylistItem = array of TPlaylistItem; TPlaylist = record Name: String; Filename: String; Items: APlaylistItem; end; APlaylist = array of TPlaylist; //---------- //TPlaylistManager - Class for Managing Playlists (Loading, Displaying, Saving) //---------- TPlaylistManager = class private public Mode: Byte; //Current Playlist Mode for SongScreen CurPlayList: Cardinal; CurItem: Cardinal; Playlists: APlaylist; constructor Create; Procedure LoadPlayLists; Function FindSong(Artist, Title: String): Integer; Function LoadPlayList(Index: Cardinal; Filename: String): Boolean; Procedure SavePlayList(Index: Cardinal); Procedure SetPlayList(Index: Cardinal); Function AddPlaylist(Name: String): Cardinal; Procedure DelPlaylist(const Index: Cardinal); Function SongExists(const SongID: Cardinal; const iPlaylist: Integer): boolean; Procedure AddItem(const SongID: Cardinal; const iPlaylist: Integer = -1); Procedure DelItem(const iItem: Cardinal; const iPlaylist: Integer = -1); Procedure GetNames(var PLNames: array of String); Procedure GetNamesAndNumSongs(var PLNames: array of String); Function GetIndexbySongID(const SongID: Cardinal; const iPlaylist: Integer = -1): Integer; Function GetNumSongs(Index: Cardinal): integer; end; {Modes: 0: Standard Mode 1: Category Mode 2: PlayList Mode} var PlayListMan: TPlaylistManager; implementation uses USongs, ULog, UFiles, UGraphic, UThemes, SysUtils, UMusic; //---------- //Create - Construct Class - Dummy for now //---------- constructor TPlayListManager.Create; begin LoadPlayLists; end; //---------- //LoadPlayLists - Load list of Playlists from PlayList Folder //---------- Procedure TPlayListManager.LoadPlayLists; var SR: TSearchRec; Len: Integer; begin SetLength(Playlists, 0); if FindFirst(PlayListPath + '*.upl', 0, SR) = 0 then begin repeat Len := Length(Playlists); SetLength(Playlists, Len +1); if not LoadPlayList (Len, Sr.Name) then SetLength(Playlists, Len); until FindNext(SR) <> 0; FindClose(SR); end; end; Function TPlayListManager.FindSong(Artist, Title: String): Integer; var I: Integer; begin Result := -1; For I := low(CatSongs.Song) to high(CatSongs.Song) do begin if (CatSongs.Song[I].Title = Title) AND (CatSongs.Song[I].Artist = Artist) then begin Result := I; Break; end; end; end; //---------- //LoadPlayList - Load a Playlist in the Array //---------- Function TPlayListManager.LoadPlayList(Index: Cardinal; Filename: String): Boolean; var F: TextFile; Line: String; PosDelimiter: Integer; SongID: Integer; Len: Integer; begin if not FileExists(PlayListPath + Filename) then begin Log.LogError('Could not load Playlist: ' + Filename); Result := False; Exit; end; Result := True; //Load File AssignFile(F, PlayListPath + FileName); Reset(F); //Set Filename PlayLists[Index].Filename := Filename; PlayLists[Index].Name := ''; //Read Until End of File While not Eof(F) do begin //Read Curent Line Readln(F, Line); if (Length(Line) > 0) then begin PosDelimiter := Pos(':', Line); if (PosDelimiter <> 0) then begin //Comment or Name String if (Line[1] = '#') then begin //Found Name Value if (Uppercase(Trim(copy(Line, 2, PosDelimiter - 2))) = 'NAME') then PlayLists[Index].Name := Trim(copy(Line, PosDelimiter + 1,Length(Line) - PosDelimiter)) end //Song Entry else begin SongID := FindSong(Trim(copy(Line, 1, PosDelimiter - 1)), Trim(copy(Line, PosDelimiter + 1, Length(Line) - PosDelimiter))); if (SongID <> -1) then begin Len := Length(PlayLists[Index].Items); SetLength(PlayLists[Index].Items, Len + 1); PlayLists[Index].Items[Len].SongID := SongID; PlayLists[Index].Items[Len].Artist := Trim(copy(Line, 1, PosDelimiter - 1)); PlayLists[Index].Items[Len].Title := Trim(copy(Line, PosDelimiter + 1, Length(Line) - PosDelimiter)); end else Log.LogError('Could not find Song in Playlist: ' + PlayLists[Index].Filename + ', ' + Line); end; end; end; end; //If no special name is given, use Filename if PlayLists[Index].Name = '' then begin PlayLists[Index].Name := ChangeFileExt(FileName, ''); end; //Finish (Close File) CloseFile(F); end; //---------- //SavePlayList - Saves the specified Playlist //---------- Procedure TPlayListManager.SavePlayList(Index: Cardinal); var F: TextFile; I: Integer; begin if (Not FileExists(PlaylistPath + Playlists[Index].Filename)) OR (Not FileisReadOnly(PlaylistPath + Playlists[Index].Filename)) then begin //open File for Rewriting AssignFile(F, PlaylistPath + Playlists[Index].Filename); try try Rewrite(F); //Write Version (not nessecary but helpful) WriteLn(F, '######################################'); WriteLn(F, '#Ultrastar Deluxe Playlist Format v1.0'); WriteLn(F, '#Playlist "' + Playlists[Index].Name + '" with ' + InttoStr(Length(Playlists[Index].Items)) + ' Songs.'); WriteLn(F, '######################################'); //Write Name Information WriteLn(F, '#Name: ' + Playlists[Index].Name); //Write Song Information WriteLn(F, '#Songs:'); For I := 0 to high(Playlists[Index].Items) do begin WriteLn(F, Playlists[Index].Items[I].Artist + ' : ' + Playlists[Index].Items[I].Title); end; except log.LogError('Could not write Playlistfile "' + Playlists[Index].Name + '"'); end; finally CloseFile(F); end; end; end; //---------- //SetPlayList - Display a Playlist in CatSongs //---------- Procedure TPlayListManager.SetPlayList(Index: Cardinal); var I: Integer; begin If (Index > High(PlayLists)) then exit; //Hide all Songs For I := 0 to high(CatSongs.Song) do CatSongs.Song[I].Visible := False; //Show Songs in PL For I := 0 to high(PlayLists[Index].Items) do begin if (ScreenSong.Mode=smNormal) or not CatSongs.Song[PlayLists[Index].Items[I].SongID].isDuet then CatSongs.Song[PlayLists[Index].Items[I].SongID].Visible := True; end; //Set CatSongsMode + Playlist Mode CatSongs.CatNumShow := -3; Mode := 2; //Set CurPlaylist CurPlaylist := Index; //Show Cat in Topleft: ScreenSong.ShowCatTLCustom(Format(Theme.Playlist.CatText,[Playlists[Index].Name])); //Fix SongSelection ScreenSong.Interaction := 0; ScreenSong.SelectNext; ScreenSong.FixSelected; //Play correct Music ScreenSong.ChangeMusic; end; //---------- //AddPlaylist - Adds a Playlist and Returns the Index //---------- Function TPlayListManager.AddPlaylist(Name: String): Cardinal; var I: Integer; begin Result := Length(Playlists); SetLength(Playlists, Result + 1); Playlists[Result].Name := Name; I := 1; if (not FileExists(PlaylistPath + Name + '.upl')) then Playlists[Result].Filename := Name + '.upl' else begin repeat Inc(I); until not FileExists(PlaylistPath + Name + InttoStr(I) + '.upl'); Playlists[Result].Filename := Name + InttoStr(I) + '.upl'; end; //Save new Playlist SavePlayList(Result); end; //---------- //DelPlaylist - Deletes a Playlist //---------- Procedure TPlayListManager.DelPlaylist(const Index: Cardinal); var I: Integer; Filename: String; begin If Index > High(Playlists) then Exit; Filename := PlaylistPath + Playlists[Index].Filename; //If not FileExists or File is not Writeable then exit If (Not FileExists(Filename)) OR (FileisReadOnly(Filename)) then Exit; //Delete Playlist from FileSystem if Not DeleteFile(Filename) then Exit; //Delete Playlist from Array //move all PLs to the Hole For I := Index to High(Playlists)-1 do PlayLists[I] := PlayLists[I+1]; //Delete last Playlist SetLength (Playlists, High(Playlists)); //If Playlist is Displayed atm //-> Display Songs if (CatSongs.CatNumShow = -3) and (Index = CurPlaylist) then begin ScreenSong.UnLoadDetailedCover; ScreenSong.HideCatTL; CatSongs.SetFilter('', 0); ScreenSong.Interaction := 0; ScreenSong.FixSelected; ScreenSong.ChangeMusic; end; end; Function TPlayListManager.SongExists(const SongID: Cardinal; const iPlaylist: Integer): boolean; var P: Cardinal; I: Cardinal; begin Result := false; if iPlaylist = -1 then P := CurPlaylist else if (iPlaylist >= 0) AND (iPlaylist <= high(Playlists)) then P := iPlaylist else exit; if (SongID <= High(CatSongs.Song)) AND (NOT CatSongs.Song[SongID].Main) then begin for I := 0 to High(Playlists[P].Items) do begin if (Playlists[P].Items[I].SongID = SongID) then Result := true; end; end; end; //---------- //AddItem - Adds an Item to a specific Playlist //---------- Procedure TPlayListManager.AddItem(const SongID: Cardinal; const iPlaylist: Integer); var P: Cardinal; Len: Cardinal; begin if iPlaylist = -1 then P := CurPlaylist else if (iPlaylist >= 0) AND (iPlaylist <= high(Playlists)) then P := iPlaylist else exit; if (SongID <= High(CatSongs.Song)) AND (NOT CatSongs.Song[SongID].Main) then begin Len := Length(Playlists[P].Items); SetLength(Playlists[P].Items, Len + 1); Playlists[P].Items[Len].SongID := SongID; Playlists[P].Items[Len].Title := CatSongs.Song[SongID].Title; Playlists[P].Items[Len].Artist := CatSongs.Song[SongID].Artist; //Save Changes SavePlayList(P); //Correct Display when Editing current Playlist if (CatSongs.CatNumShow = -3) and (P = CurPlaylist) then SetPlaylist(P); end; end; //---------- //DelItem - Deletes an Item from a specific Playlist //---------- Procedure TPlayListManager.DelItem(const iItem: Cardinal; const iPlaylist: Integer); var I: Integer; P: Cardinal; begin if iPlaylist = -1 then P := CurPlaylist else if (iPlaylist >= 0) AND (iPlaylist <= high(Playlists)) then P := iPlaylist else exit; if (iItem <= high(Playlists[P].Items)) then begin //Move all entrys behind deleted one to Front For I := iItem to High(Playlists[P].Items) - 1 do Playlists[P].Items[I] := Playlists[P].Items[I + 1]; //Delete Last Entry SetLength(PlayLists[P].Items, Length(PlayLists[P].Items) - 1); //Save Changes SavePlayList(P); end; //Delete Playlist if Last Song is deleted if (Length(PlayLists[P].Items) = 0) then begin DelPlaylist(P); end //Correct Display when Editing current Playlist else if (CatSongs.CatNumShow = -3) and (P = CurPlaylist) then SetPlaylist(P); end; //---------- //GetNames - Writes Playlist Names in a Array //---------- Procedure TPlayListManager.GetNames(var PLNames: array of String); var I: Integer; Len: Integer; begin Len := High(Playlists); if (Length(PLNames) <> Len + 1) then exit; For I := 0 to Len do PLNames[I] := Playlists[I].Name; end; //---------- //GetNamesAndNumSongs - Writes Playlist Names + Num Songs in an Array //---------- Procedure TPlayListManager.GetNamesAndNumSongs(var PLNames: array of String); var I: Integer; Len: Integer; begin Len := High(Playlists); if (Length(PLNames) <> Len + 1) then exit; For I := 0 to Len do PLNames[I] := Playlists[I].Name + ' ( ' + IntToStr(GetNumSongs(I)) + ' Songs)'; end; //---------- //GetIndexbySongID - Returns Index in the specified Playlist of the given Song //---------- Function TPlayListManager.GetIndexbySongID(const SongID: Cardinal; const iPlaylist: Integer): Integer; var P: Integer; I: Integer; begin if iPlaylist = -1 then P := CurPlaylist else if (iPlaylist >= 0) AND (iPlaylist <= high(Playlists)) then P := iPlaylist else exit; Result := -1; For I := 0 to high(Playlists[P].Items) do begin if (Playlists[P].Items[I].SongID = SongID) then begin Result := I; Break; end; end; end; function TPlayListManager.GetNumSongs(Index: Cardinal): integer; var I: integer; begin Result := 0; //Count Songs in Playlist For I := 0 to high(PlayLists[Index].Items) do begin if (ScreenSong.Mode=smNormal) or not CatSongs.Song[PlayLists[Index].Items[I].SongID].isDuet then Inc(Result); end; end; end.