Skip to content

Commit

Permalink
Playlist Support is functional:
Browse files Browse the repository at this point in the history
    Allow multiple playlist directories.
    Always add the BeatDrop playlist folder.
    Playlist show in order defined in the playlist file.
    Handle bad or unknown base64 data for now.
  • Loading branch information
halsafar committed Aug 4, 2018
1 parent 1989613 commit 5bbbabc
Show file tree
Hide file tree
Showing 16 changed files with 773 additions and 12 deletions.
18 changes: 18 additions & 0 deletions SongBrowserPlugin/DataAccess/Playlist.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SongBrowserPlugin.DataAccess
{
public class Playlist
{
public String playlistTitle { get; set; }
public String playlistAuthor { get; set; }
public string image { get; set; }
public List<PlaylistSong> songs { get; set; }

public String playlistPath;
}
}
104 changes: 104 additions & 0 deletions SongBrowserPlugin/DataAccess/PlaylistReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
using SimpleJSON;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace SongBrowserPlugin.DataAccess
{
public class PlaylistsReader
{
private static Logger _log = new Logger("PlaylistReader");

private List<String> _PlaylistsDirectories = new List<string>();

private List<Playlist> _CachedPlaylists;

public List<Playlist> Playlists
{
get
{
return _CachedPlaylists;
}
}

public PlaylistsReader(String playlistsDirectory)
{
_PlaylistsDirectories.Add(playlistsDirectory);

// Hack, add beatdrop location
String localAppDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
String beatDropPlaylistPath = Path.Combine(localAppDataPath, "Programs", "BeatDrop", "playlists");

_PlaylistsDirectories.Add(beatDropPlaylistPath);
}

public void UpdatePlaylists()
{
_CachedPlaylists = new List<Playlist>();

foreach (String path in _PlaylistsDirectories)
{
_log.Debug("Reading playlists located at: {0}", path);
if (!Directory.Exists(path))
{
_log.Info("Playlist path does not exist: {0}", path);
continue;
}

string[] files = Directory.GetFiles(path);
foreach (string file in files)
{
_log.Debug("Checking file {0}", file);
if (Path.GetExtension(file) == ".json")
{
Playlist p = ParsePlaylist(file);
_CachedPlaylists.Add(p);
}
}
}
}

public static Playlist ParsePlaylist(String path)
{
try
{
if (!File.Exists(path))
{
_log.Debug("Playlist file no longer exists: {0}", path);
return null;
}

_log.Debug("Parsing playlist at {0}", path);
String json = File.ReadAllText(path);
Playlist playlist = new Playlist();

JSONNode playlistNode = JSON.Parse(json);

playlist.image = playlistNode["image"];
playlist.playlistTitle = playlistNode["playlistTitle"];
playlist.playlistAuthor = playlistNode["playlistAuthor"];
playlist.songs = new List<PlaylistSong>();

foreach (JSONNode node in playlistNode["songs"].AsArray)
{
PlaylistSong song = new PlaylistSong();
song.key = node["key"];
song.songName = node["songName"];

playlist.songs.Add(song);
}

playlist.playlistPath = path;
return playlist;
}
catch (Exception e)
{
_log.Exception("Exception parsing playlist: ", e);
}

return null;
}
}
}
14 changes: 14 additions & 0 deletions SongBrowserPlugin/DataAccess/PlaylistSong.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SongBrowserPlugin.DataAccess
{
public class PlaylistSong
{
public int key { get; set; }
public String songName { get; set; }
}
}
5 changes: 3 additions & 2 deletions SongBrowserPlugin/DataAccess/SongBrowserSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ public enum SongSortMode
Author,
Favorites,
Original,
Newest,
Newest,
PlayCount,
Difficulty,
Random,
Playlist,
Search
}

Expand All @@ -29,7 +30,7 @@ public class SongBrowserSettings

public String currentLevelId = default(String);
public String currentDirectory = default(String);

public String currentPlaylistFile = default(String);

[NonSerialized]
private static Logger Log = new Logger("SongBrowserSettings");
Expand Down
2 changes: 1 addition & 1 deletion SongBrowserPlugin/Logger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public enum LogLevel
public class Logger
{
private string loggerName;
private LogLevel _LogLevel = LogLevel.Info;
private LogLevel _LogLevel = LogLevel.Trace;
private ConsoleColor _defaultFgColor;

public Logger(string _name)
Expand Down
8 changes: 8 additions & 0 deletions SongBrowserPlugin/SongBrowserApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,14 @@ public static void InvokeBeatSaberButton(String buttonName)
/// </summary>
private void LateUpdate()
{
// playlists
if (Input.GetKeyDown(KeyCode.P))
{
MainMenuViewController mainView = Resources.FindObjectsOfTypeAll<MainMenuViewController>().First();
PlaylistFlowCoordinator view = UIBuilder.CreateFlowCoordinator<PlaylistFlowCoordinator>("PlaylistFlowCoordinator");
view.Present(mainView);
}

// z,x,c,v can be used to get into a song, b will hit continue button after song ends
if (Input.GetKeyDown(KeyCode.Z))
{
Expand Down
61 changes: 57 additions & 4 deletions SongBrowserPlugin/SongBrowserModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ public class SongBrowserModel
private Dictionary<string, int> _weights;
private Dictionary<String, DirectoryNode> _directoryTree;
private Stack<DirectoryNode> _directoryStack = new Stack<DirectoryNode>();

private GameplayMode _currentGamePlayMode;

/// <summary>
Expand Down Expand Up @@ -161,6 +162,9 @@ public String LastSelectedLevelId
}
}

/// <summary>
/// Get the last known directory the user visited.
/// </summary>
public String CurrentDirectory
{
get
Expand All @@ -175,6 +179,30 @@ public String CurrentDirectory
}
}

private Playlist _currentPlaylist;

/// <summary>
/// Manage the current playlist if one exists.
/// </summary>
public Playlist CurrentPlaylist
{
get
{
if (_currentPlaylist == null)
{
_currentPlaylist = PlaylistsReader.ParsePlaylist(this._settings.currentPlaylistFile);
}

return _currentPlaylist;
}

set
{
_settings.currentPlaylistFile = value.playlistPath;
_currentPlaylist = value;
}
}


/// <summary>
/// Constructor.
Expand Down Expand Up @@ -453,11 +481,19 @@ private void ProcessSongList()
}
}*/

Stopwatch stopwatch = Stopwatch.StartNew();

_log.Debug("Showing songs for directory: {0}", _directoryStack.Peek().Key);
List<StandardLevelSO> songList = _directoryStack.Peek().Levels;
Stopwatch stopwatch = Stopwatch.StartNew();

List<StandardLevelSO> songList = null;
if (this._settings.sortMode == SongSortMode.Playlist && this.CurrentPlaylist != null)
{
songList = null;
}
else
{
_log.Debug("Showing songs for directory: {0}", _directoryStack.Peek().Key);
songList = _directoryStack.Peek().Levels;
}

switch (_settings.sortMode)
{
case SongSortMode.Favorites:
Expand All @@ -484,6 +520,9 @@ private void ProcessSongList()
case SongSortMode.Search:
SortSearch(songList);
break;
case SongSortMode.Playlist:
SortPlaylist();
break;
case SongSortMode.Default:
default:
SortSongName(songList);
Expand Down Expand Up @@ -675,5 +714,19 @@ private void SortSongName(List<StandardLevelSO> levels)
.ThenBy(x => x.songAuthorName)
.ToList();
}

private void SortPlaylist()
{
_log.Debug("Showing songs for playlist: {0}", this.CurrentPlaylist);
List<String> playlistNameListOrdered = this.CurrentPlaylist.songs.Select(x => x.songName).ToList();
Dictionary<String, int> songNameToIndex = playlistNameListOrdered.Select((val, index) => new { Index = index, Value = val }).ToDictionary(i => i.Value, i => i.Index);
HashSet<String> songNames = new HashSet<String>(playlistNameListOrdered);
SongLoaderPlugin.OverrideClasses.CustomLevelCollectionsForGameplayModes collections = SongLoaderPlugin.SongLoader.Instance.GetPrivateField<SongLoaderPlugin.OverrideClasses.CustomLevelCollectionsForGameplayModes>("_customLevelCollectionsForGameplayModes");
List<StandardLevelSO> songList = collections.GetLevels(_currentGamePlayMode).Where(x => songNames.Contains(x.songName)).ToList();
_sortedSongs = songList
.AsQueryable()
.OrderBy(x => songNameToIndex[x.songName])
.ToList();
}
}
}
21 changes: 21 additions & 0 deletions SongBrowserPlugin/SongBrowserPlugin.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@
<Reference Include="UnityEngine.JSONSerializeModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
<HintPath>D:\Games\Steam\SteamApps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.JSONSerializeModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.Networking">
<HintPath>D:\Games\Steam\SteamApps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.Networking.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.TextRenderingModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>D:\Games\Steam\SteamApps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.TextRenderingModule.dll</HintPath>
Expand All @@ -86,14 +89,32 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>D:\Games\Steam\SteamApps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.UIModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UnityWebRequestModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>D:\Games\Steam\SteamApps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.UnityWebRequestModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UnityWebRequestWWWModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>D:\Games\Steam\SteamApps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.UnityWebRequestWWWModule.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="BeatSaverApi\BeatSaverApi.cs" />
<Compile Include="BeatSaverApi\BeatSaverAPIResults.cs" />
<Compile Include="DataAccess\Playlist.cs" />
<Compile Include="DataAccess\PlaylistReader.cs" />
<Compile Include="DataAccess\PlaylistSong.cs" />
<Compile Include="Logger.cs" />
<Compile Include="SongBrowserApplication.cs" />
<Compile Include="Plugin.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SongBrowserModel.cs" />
<Compile Include="DataAccess\SongBrowserSettings.cs" />
<Compile Include="UI\Playlists\PlaylistDetailViewController.cs" />
<Compile Include="UI\Playlists\PlaylistFlowCoordinator.cs" />
<Compile Include="UI\Playlists\PlaylistSelectionListViewController.cs" />
<Compile Include="UI\Playlists\PlaylistSelectionNavigationController.cs" />
<Compile Include="UI\Playlists\PlaylistTableView.cs" />
<Compile Include="UI\Base64Sprites.cs" />
<Compile Include="UI\CustomUIKeyboard.cs" />
<Compile Include="UI\SearchKeyboardViewController.cs" />
Expand Down
20 changes: 18 additions & 2 deletions SongBrowserPlugin/UI/Base64Sprites.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,24 @@ class Base64Sprites

public static Sprite Base64ToSprite(string base64)
{
Texture2D tex = Base64ToTexture2D(base64);
return Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), (Vector2.one / 2f));
if (base64.StartsWith("data:image/png;base64,"))
{
base64 = base64.Remove(0, "data:image/png;base64,".Length);
}

Sprite s = null;
try
{
Texture2D tex = Base64ToTexture2D(base64);
s = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), (Vector2.one / 2f));
}
catch (Exception e)
{
Console.WriteLine("Exception loading texture from base64 data.");
s = null;
}

return s;
}

public static Texture2D Base64ToTexture2D(string encodedData)
Expand Down
Loading

0 comments on commit 5bbbabc

Please sign in to comment.