aboutsummaryrefslogblamecommitdiffstats
path: root/unicode/src/base/UPlaylist.pas
blob: 744f4ce8c2eab98e6c81da35fca82850723f29ea (plain) (tree)



































                                                                        

        


                        

                       





                                         
                     




















                                                                                 
                                                                                 



                                                
                                                            




                                                                                 
                                                         






































































                                                                                                   
                                                                                            






                          
                                                        


































































































































































                                                                                                                                      
                                                                       
































































                                                                                
                                   

























































































































                                                                                                         
{* UltraStar Deluxe - Karaoke Game
 *
 * UltraStar Deluxe is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING. If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 *
 * $URL$
 * $Id$
 *}

unit UPlaylist;

interface

{$IFDEF FPC}
  {$MODE Delphi}
{$ENDIF}

{$I switches.inc}

uses
  USong,
  UPath;

type
  TPlaylistItem = record
    Artist: UTF8String;
    Title:  UTF8String;
    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:         TSingMode;     //Current Playlist Mode for SongScreen
      CurPlayList:  Cardinal;
      CurItem:      Cardinal;

      Playlists:    APlaylist;

      constructor Create;
      Procedure   LoadPlayLists;
      Function    LoadPlayList(Index: Cardinal; const Filename: String): Boolean;
      Procedure   SavePlayList(Index: Cardinal);

      Procedure   SetPlayList(Index: Cardinal);

      Function    AddPlaylist(const Name: string): Cardinal;
      Procedure   DelPlaylist(const Index: Cardinal);

      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);
      Function    GetIndexbySongID(const SongID: Cardinal; const iPlaylist: Integer = -1): Integer;
    end;

    {Modes:
      0: Standard Mode
      1: Category Mode
      2: PlayList Mode}

  var
    PlayListMan:  TPlaylistManager;


implementation

uses USongs,
     ULog,
     UMain,
     //UFiles,
     UGraphic,
     UThemes,
     SysUtils;

//----------
//Create - Construct Class - Dummy for now
//----------
constructor TPlayListManager.Create;
begin
  inherited;
  LoadPlayLists;
end;

//----------
//LoadPlayLists - Load list of Playlists from PlayList Folder
//----------
Procedure   TPlayListManager.LoadPlayLists;
var
  SR:   TSearchRec;
  Len:  Integer;
  PlayListBuffer: TPlayList;
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)
      else
      begin
        // Sort the Playlists - Insertion Sort
        PlayListBuffer := Playlists[Len];
        Dec(Len);
        while (Len >= 0) AND (CompareText(Playlists[Len].Name, PlayListBuffer.Name) >= 0) do
        begin
            Playlists[Len+1] := Playlists[Len];
            Dec(Len);
        end;
        Playlists[Len+1] := PlayListBuffer;
      end;

    until FindNext(SR) <> 0;
    FindClose(SR);
  end;  
end;

//----------
//LoadPlayList - Load a Playlist in the Array
//----------
Function    TPlayListManager.LoadPlayList(Index: Cardinal; const Filename: String): Boolean;
  var
    F: TextFile;
    Line: String;
    PosDelimiter: Integer;
    SongID: Integer;
    Len: Integer;

  Function FindSong(Artist, Title: UTF8String): 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;
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 (Int(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
    CatSongs.Song[PlayLists[Index].Items[I].SongID].Visible := True;
  end;

  //Set CatSongsMode + Playlist Mode
  CatSongs.CatNumShow := -3;
  Mode := smPlayListRandom;

  //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(const Name: string): Cardinal;
var
  I: Integer;
begin
  Result := Length(Playlists);
  SetLength(Playlists, Result + 1);
  
  // Sort the Playlists - Insertion Sort
  while (Result > 0) AND (CompareText(Playlists[Result - 1].Name, Name) >= 0) do
  begin
    Dec(Result);
    Playlists[Result+1] := Playlists[Result];
  end;
  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 Int(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('', fltAll);
    ScreenSong.Interaction := 0;
    ScreenSong.FixSelected;
    ScreenSong.ChangeMusic;
  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 (Int(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 (Int(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;

//----------
//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
  Result := -1;

  if iPlaylist = -1 then
    P := CurPlaylist
  else if (iPlaylist >= 0) AND (iPlaylist <= high(Playlists)) then
    P := iPlaylist
  else
    exit;

  For I := 0 to high(Playlists[P].Items) do
  begin
    if (Playlists[P].Items[I].SongID = Int(SongID)) then
    begin
      Result := I;
      Break;
    end;
  end;
end;

end.