rott/kf_sources/Engine/Classes/StreamPlaylistManager.uc
2026-07-14 20:27:09 +07:00

692 lines
17 KiB
Ucode

//==============================================================================
// 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<StreamPlaylist> 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<PlaylistParser> ParserType;
var() editconst noexport editinline editconstarray array<PlaylistParserBase> Parsers;
// =====================================================================================================================
// =====================================================================================================================
// Initialization
// =====================================================================================================================
// =====================================================================================================================
delegate ChangedActivePlaylist( StreamPlaylist NewPlaylist );
function Initialize( StreamInterface InFileManager )
{
FileManager = InFileManager;
InitializePlaylists();
InitializeParsers();
}
protected function InitializePlaylists()
{
local array<string> 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<PlaylistParserBase> ParseClass;
for ( i = 0; i < ParserType.Length; i++ )
{
if ( ParserType[i].ParserClass != "" )
{
ParseClass = class<PlaylistParserBase>(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<string> 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")
}