//============================================================================== // Created on: 10/14/2003 // Manages custom playlists // // Written by Ron Prestenback // © 2003, Epic Games, Inc. All Rights Reserved //============================================================================== class StreamPlaylistManager extends StreamBase Config(UPlaylists); var() editconst protected config int CurrentPlaylist; // Index of current playlist var() editinline editconst noexport StreamInterface FileManager; var() editinline editconstarray protected array Playlists; var() protected bool bDisableNotification; var() transient noexport protected bool bDirty; var() protected config bool bShuffle, bShuffleAll, bRepeat, bRepeatAll; var() localized string DefaultPlaylistName; struct PlaylistParser { var() EStreamPlaylistType Type; var() string ParserClass; }; var() config array ParserType; var() editconst noexport editinline editconstarray array Parsers; // ===================================================================================================================== // ===================================================================================================================== // Initialization // ===================================================================================================================== // ===================================================================================================================== delegate ChangedActivePlaylist( StreamPlaylist NewPlaylist ); function Initialize( StreamInterface InFileManager ) { FileManager = InFileManager; InitializePlaylists(); InitializeParsers(); } protected function InitializePlaylists() { local array PlaylistNames; local StreamPlaylist NewList; local int i; PlaylistNames = GetPerObjectNames("UPlaylists", "StreamPlaylist"); for ( i = 0; i < PlaylistNames.Length; i++ ) { if ( PlaylistNames[i] == "" ) continue; NewList = CreatePlaylist(PlaylistNames[i]); AppendPlaylist(NewList); } if ( Playlists.Length == 0 ) CreateDefaultPlaylist(); else if ( !ActivatePlaylist(CurrentPlaylist) ) ActivatePlaylist(0); } protected function InitializeParsers() { local int i, j; local class ParseClass; for ( i = 0; i < ParserType.Length; i++ ) { if ( ParserType[i].ParserClass != "" ) { ParseClass = class(DynamicLoadObject(ParserType[i].ParserClass, class'Class')); if ( ParseClass != None ) { j = Parsers.Length; Parsers[j] = new(Self) ParseClass; Parsers[j].SetType(ParserType[i].Type); } } } } protected function StreamPlaylist CreateDefaultPlaylist() { local int i; local string Nothing; Nothing = DefaultPlaylistName; i = AddPlaylist(Nothing); if ( ValidIndex(i) && ActivatePlaylist(i) ) return Playlists[CurrentPlaylist]; return None; } // ===================================================================================================================== // ===================================================================================================================== // Playlist Management // ===================================================================================================================== // ===================================================================================================================== function bool ActivatePlaylist( int ListIndex, optional bool bNoFail ) { if ( !ValidIndex(ListIndex) ) { if ( bNoFail ) return False; // log("Wasn't a valid index:"$ListIndex,'MusicPlayer'); if ( GetRepeatAll() ) { if ( ListIndex < 0 ) ListIndex = Playlists.Length - 1; else if ( ListIndex >= Playlists.Length ) ListIndex = 0; if ( !ValidIndex(ListIndex) ) return false; } else return false; } bDirty = bDirty || ListIndex != CurrentPlaylist; Playlists[ListIndex].InitializePlaylist(FileManager); CurrentPlaylist = ListIndex; if ( !bDisableNotification ) ChangedActivePlaylist(Playlists[ListIndex]); return true; } function int AddPlaylist( out string NewPlaylistName ) { local string Str; local int i; if ( NewPlaylistName == "" ) NewPlaylistName = DefaultPlaylistName; Str = NewPlaylistName; while ( ValidName(NewPlaylistName) ) NewPlaylistName = Str $ i++; return AppendPlaylist( CreatePlaylist(NewPlaylistName) ); } protected function int AppendPlaylist( StreamPlaylist Playlist ) { local int i; if ( Playlist == None ) return -1; i = FindPlaylistIndex(Playlist); if ( i == -1 ) i = Playlists.Length; // log("Appending new playlist...playlist number "$i); Playlists[i] = Playlist; bDirty = True; return i; } function bool RemovePlaylist( string PlaylistName ) { local int i; // log("Removing playlist "$PlaylistName); i = FindNameIndex(PlaylistName); if ( i != -1 ) return RemovePlaylistAt(i); return false; } function bool RemovePlaylistAt( int Index ) { local bool bWasActive; if ( !ValidIndex(Index) ) return false; // log("Removing playlist at "$index); bWasActive = CurrentPlaylist == Index; // Check if this is the active playlist - if so, set the default active Playlists[Index].ClearConfig(); Playlists.Remove(Index,1); if ( bWasActive ) ActivatePlaylist(0); return true; } function bool RenamePlaylist( int Index, out string NewName ) { local StreamPlaylist Temp; local string Str; local int i; // log("RenamePlaylist() Index:"$Index@"CurrentName:"$Playlists[Index].GetTitle()@"NewName:"$NewName); if ( !ValidIndex(Index) || NewName == "" ) return false; Str = NewName; while ( ValidName(NewName) ) NewName = Str $ i++; Temp = CreatePlaylist(NewName); if ( Temp == None ) return false; Temp.ReplaceWith(Playlists[Index]); Playlists[Index].ClearConfig(); Playlists[Index] = Temp; Playlists[Index].Save(); if ( !bDisableNotification ) ChangedActivePlaylist(Playlists[Index]); return true; } function bool AddToPlaylist( int PlaylistIndex, string Path, optional bool bSkipNotification ) { if ( !ValidIndex(PlaylistIndex) ) { if ( !ValidIndex(CurrentPlaylist) ) return false; PlaylistIndex = CurrentPlaylist; } return InsertInPlaylist( PlaylistIndex, -1, Path, bSkipNotification ); } function bool InsertInPlaylist( int PlaylistIndex, int InsertPosition, string Path, optional bool bSkipNotification ) { local EFileType Type; local bool bResult; if ( !ValidIndex(PlaylistIndex) ) return false; Type = ConvertToFileType(Path); Playlists[PlaylistIndex].InitializePlaylist(FileManager); // log("PlaylistManager.AddToPlaylist() PlaylistIndex:"$PlaylistIndex@"InsertPosition:"$InsertPosition@"Path:"$Path@" Type:"$GetEnum(enum'EFileType',Type)@"Path:"$Path); switch ( Type ) { case FILE_None: // directory bDisableNotification = True; bResult = AddDirectory( PlaylistIndex, InsertPosition, Path, True ); bDisableNotification = False; if ( bResult && !bSkipNotification ) Playlists[PlaylistIndex].OnPlaylistChanged(); return bResult; case FILE_Playlist: // importing a playlist bDisableNotification = True; bResult = ImportPlaylist(PlaylistIndex, InsertPosition, Path); bDisableNotification = False; if ( bResult && !bSkipNotification ) Playlists[PlaylistIndex].OnPlaylistChanged(); return bResult; case FILE_Stream: // adding a song return Playlists[PlaylistIndex].InsertSong(InsertPosition, Path, bDisableNotification || bSkipNotification) != -1; } return false; } function bool RemoveFromCurrentPlaylist( string Path, optional bool bSkipNotification ) { // log("RemoveFromCurrentPlaylist CurrentPlaylist:"$CurrentPlaylist@"Path:"$Path); if ( ValidIndex(CurrentPlaylist) ) return Playlists[CurrentPlaylist].RemoveSong(Path, bSkipNotification); return false; } function bool ClearCurrentPlaylist() { if ( !ValidIndex(CurrentPlaylist) ) return false; return Playlists[CurrentPlaylist].ClearPlaylist(); } function EStreamPlaylistType GetPlaylistType( string Path ) { local string Ext; Ext = ParseExtension(Path); switch ( Locs(Ext) ) { case "m3u": return SPT_M3U; case "b4s": return SPT_B4S; case "pls": return SPT_PLS; } return SPT_None; } // TODO hook up non-recursive function bool AddDirectory( int PlaylistIndex, int InsertPosition, string Path, bool bRecurseDirectories ) { local int i; local bool bValue; local array Results; // First, check for any directories if ( bRecurseDirectories ) { if ( FileManager.GetDirectoryContents(Results,Path,FILE_Directory) ) { for ( i = Results.Length - 1; i >= 0; i-- ) bValue = AddDirectory(PlaylistIndex,InsertPosition, Path $ Results[i] $ GetPathSeparator(), True) || bValue; } } Results.Remove(0, Results.Length); if ( FileManager.GetDirectoryContents(Results,Path,FILE_Stream) ) { if ( !Playlists[PlaylistIndex].ValidStreamIndex(InsertPosition) ) InsertPosition = Playlists[PlaylistIndex].GetPlaylistLength(); for ( i = Results.Length - 1; i >= 0; i-- ) bValue = Playlists[PlaylistIndex].InsertSong(InsertPosition, Path $ Results[i], bDisableNotification) != -1 || bValue; } return bValue; } function bool ImportPlaylist( int PlaylistIndex, int InsertPosition, string Path ) { local int i; local EStreamPlaylistType Type; // log("ImportPlaylist() PlaylistIndex:"$PlaylistIndex@"InsertPosition:"$InsertPosition@"Path:"$Path); Type = GetPlaylistType(Path); for ( i = 0; i < Parsers.Length; i++ ) if ( Parsers[i].GetType() == Type ) return Parsers[i].Import(PlaylistIndex, InsertPosition, Path); return false; } // Returns the next song in the playlist function string NextSong( optional bool bForce ) { local StreamPlaylist List; local Stream S; local string Str; if ( GetShuffleAll() || GetShuffle() ) return GetRandomSong(); List = GetCurrentPlaylist(); if ( List == None ) { log("PlaylistManager.NextSong() - no playlists found!",'MusicPlayer'); return ""; } if ( GetRepeat() ) { S = List.GetCurrentStream(); if ( S != None ) return S.GetPath(); } else { Str = List.NextSong( bForce || GetRepeat() ); if ( Str == "" && GetRepeatAll() && ActivatePlaylist(CurrentPlaylist+1) ) Str = Playlists[CurrentPlaylist].NextSong(bForce); if ( Str != "" ) return Str; } // log("PlaylistManager.NextSong() - last song reached.",'MusicPlayer'); return ""; } function string PrevSong( optional bool bForce ) { local StreamPlaylist List; local Stream S; local string str; if ( GetShuffleAll() || GetShuffle() ) return GetRandomSong(); List = GetCurrentPlaylist(); if ( List == None ) { log("PlaylistManager.PrevSong() - no playlists found!",'MusicPlayer'); return ""; } if ( GetRepeat() ) { S = List.GetCurrentStream(); if ( S != None ) return S.GetPath(); } else { Str = List.PrevSong( bForce || GetRepeat() ); if ( Str == "" && GetRepeatAll() && ActivatePlaylist(CurrentPlaylist-1) ) Str = Playlists[CurrentPlaylist].PrevSong(bForce); if ( Str != "" ) return Str; } // log("PlaylistManager.PrevSong() - last song reached.",'MusicPlayer'); return ""; } function string GetRandomSong() { local StreamPlaylist List; if ( GetShuffle() ) List = GetCurrentPlaylist(); else if ( GetShuffleAll() ) List = GetRandomPlayList(); if ( List != None ) return List.GetRandomSong(); return ""; } // ===================================================================================================================== // ===================================================================================================================== // Playlist Query // ===================================================================================================================== // ===================================================================================================================== function int GetCurrentIndex() { if ( ValidIndex(CurrentPlaylist) ) return CurrentPlaylist; return -1; } function StreamPlaylist GetCurrentPlaylist() { if ( ValidIndex(CurrentPlaylist) ) return Playlists[CurrentPlaylist]; if ( ActivatePlaylist(0) ) return Playlists[0]; return CreateDefaultPlaylist(); } function StreamPlaylist GetRandomPlaylist() { local int i, idx; if ( Playlists.Length == 0 ) return None; idx = Rand(Playlists.Length - 1); while ( ++i < 10 ) { if ( ActivatePlaylist(idx) ) return Playlists[CurrentPlaylist]; idx = Rand(Playlists.Length - 1); } return None; } function StreamPlaylist GetPlaylistAt( int idx ) { if ( !ValidIndex(idx) ) return None; return Playlists[idx]; } function int GetPlaylistCount() { return Playlists.Length; } // Current playlist interaction function bool ValidIndex( int Index ) { return Index >= 0 && Index < Playlists.Length; } function int FindNameIndex( string PlaylistName ) { local int i; if ( PlaylistName == "" ) return -1; for ( i = 0; i < Playlists.Length; i++ ) if ( Playlists[i].GetTitle() ~= PlaylistName ) return i; return -1; } function int FindPlaylistIndex( StreamPlaylist Playlist ) { local int i; if ( Playlist == None ) return -1; for ( i = 0; i < Playlists.Length; i++ ) if ( Playlists[i] == Playlist ) return i; return -1; } function bool ValidName( string Test ) { local int i; for ( i = 0; i < Playlists.Length; i++ ) if ( Test ~= Playlists[i].GetTitle() ) return true; return false; } function bool GetShuffle() { return bShuffle; } function bool GetShuffleAll() { return bShuffleAll; } function bool GetRepeat() { return bRepeat; } function bool GetRepeatAll() { return bRepeatAll; } // ===================================================================================================================== // ===================================================================================================================== // Internal // ===================================================================================================================== // ===================================================================================================================== function SetShuffle( bool bEnable ) { bDirty = bDirty || bEnable != bShuffle; bShuffle = bEnable; if ( bEnable && bShuffleAll ) SetShuffleAll(False); } function SetShuffleAll( bool bEnable ) { bDirty = bDirty || bEnable != bShuffleAll; bShuffleAll = bEnable; if ( bEnable && bShuffle ) SetShuffle( False ); } function SetRepeat( bool bEnable ) { bDirty = bDirty || bEnable != bRepeat; bRepeat = bEnable; if ( bEnable && bRepeatAll ) SetRepeatAll(False); } function SetRepeatAll( bool bEnable ) { bDirty = bDirty || bEnable != bRepeatAll; bRepeatAll = bEnable; if ( bEnable && bRepeat ) SetRepeat(False); } protected function StreamPlaylist CreatePlaylist(string PlaylistName) { local StreamPlaylist List; if ( PlaylistName == "" ) return None; List = new(None, Repl(PlaylistName, " ", Chr(27))) class'StreamPlaylist'; if ( List != None ) { List.SetTitle( Repl(PlaylistName, Chr(27), " ") ); List.Save(); } return List; } function bool HandleDebugExec( string Command, string Param ) { local int i; local bool result; if ( Super.HandleDebugExec(Command,Param) ) return true; switch ( Locs(command) ) { case "activate": if ( Playlists.Length > 0 ) ActivatePlaylist(0); else ActivatePlaylist(int(Param)); log("Active Playlist:"$Playlists[CurrentPlaylist].GetTitle()@"Tracks:"$Playlists[CurrentPlaylist].GetPlaylistLength(),'MusicPlayer'); break; case "lists": log(" === All existing playlists === ",'MusicPlayer'); for ( i = 0; i < Playlists.Length; i++ ) log(" Playlist"@i@" '"$Playlists[i].GetTitle(),'MusicPlayer'); } for (i = 0; i < Playlists.Length; i++ ) result = Playlists[i].HandleDebugExec(Command,Param) || result; return result; } function Save() { local int i; for ( i = 0; i < Playlists.Length; i++ ) Playlists[i].Save(); if ( !bDirty ) return; SaveConfig(); bDirty = False; } function string GetCurrentTitle() { return Playlists[GetCurrentIndex()].GetTitle(); } DefaultProperties { DefaultPlaylistName="New Playlist" bRepeatAll=True ParserType(0)=(Type=SPT_B4S,ParserClass="Engine.B4SParser") ParserType(1)=(Type=SPT_M3U,ParserClass="Engine.M3UParser") ParserType(2)=(Type=SPT_PLS,ParserClass="Engine.PLSParser") }