using System.IO;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Robust.Shared.ContentPack;
using Robust.Shared.Utility;
namespace Content.Client.Audio.Midi;
///
/// Handles storage/management of MIDI files stored inside the user data directory.
///
[PublicAPI]
public sealed partial class MidiFileCollectionManager : IPostInjectInit
{
///
/// Directory path to use inside UserData for storing MIDIs.
///
public static readonly ResPath UserMidiDirectory = new("/UserMidis/");
private const string SawmillCategory = "midifilecollection";
[Dependency] private IResourceManager _resManager = default!;
[Dependency] private ILogManager _logManager = default!;
private ISawmill _sawmill = default!;
private readonly List _filePaths = [];
///
/// Raised after a MIDI file has been added to the library. Contains added file path as argument.
///
public event Action? MidiFileAdded;
///
/// Raised after a MIDI file has been removed from the library. Contains removed file path as argument.
///
public event Action? MidiFileRemoved;
///
/// Raised after more than one or two library changes occured at once. (i.e. initial load or when all items deleted)
///
public event Action? MidiFilesReset;
///
public void PostInject()
{
EnsureMidiDirectoryExists();
ReloadLibrary();
_sawmill = _logManager.GetSawmill(SawmillCategory);
}
///
/// Returns the binary content of the given MIDI file.
///
/// MIDI file path to get.
/// MIDI binary as a byte array or an empty byte array if the file doesn't exist.
public byte[] GetMidiData(ResPath filePath)
{
try
{
var fullPath = UserMidiDirectory / filePath;
return _resManager.UserData.ReadAllBytes(fullPath);
}
catch (Exception e)
{
_sawmill.Error($"Failed to read MIDI data from '{filePath}': {e.Message}");
return [];
}
}
///
/// Returns an enumeration of all available MIDI files.
///
/// An enumeration of MIDI file paths.
public IEnumerable GetMidiFiles()
{
return _filePaths;
}
///
/// Stores the given byte stream with the given file path inside the directory.
///
/// File path to write.
/// Binary data to write.
/// Raises on success.
public async Task AddMidiFile(ResPath filePath, Stream data)
{
try
{
await using var file = _resManager.UserData.OpenWrite(UserMidiDirectory / filePath);
await data.CopyToAsync(file);
_filePaths.Add(filePath);
MidiFileAdded?.Invoke(filePath);
return true;
}
catch (Exception e)
{
_sawmill.Error($"Failed to store MIDI file '{filePath}' in library: {e.Message}");
return false;
}
}
///
/// Stores the given byte array with the given file path inside the directory.
///
/// File path to write.
/// Binary data to write.
/// Raises on success.
public async Task AddMidiFile(ResPath filePath, byte[] data)
{
return await AddMidiFile(filePath, new MemoryStream(data));
}
///
/// Renames a MIDI file inside the library.
///
/// Current file path
/// New file path
/// Raises and on success.
public bool RenameMidiFile(ResPath oldPath, ResPath newPath)
{
try
{
var fullOldPath = UserMidiDirectory / oldPath;
var fullNewPath = UserMidiDirectory / newPath;
fullOldPath = fullOldPath.Clean();
fullNewPath = fullNewPath.Clean();
_resManager.UserData.Rename(fullOldPath, fullNewPath);
_filePaths.Remove(oldPath);
MidiFileRemoved?.Invoke(oldPath);
_filePaths.Add(newPath);
MidiFileAdded?.Invoke(newPath);
return true;
}
catch (Exception e)
{
_sawmill.Error($"Failed to rename MIDI file '{oldPath}' with '{newPath}': {e.Message}");
return false;
}
}
///
/// Permanently removes the given MIDI file if it exists inside .
///
/// File path to remove.
/// Raises
public void RemoveMidiFile(ResPath filePath)
{
DeleteMidiFile(filePath);
_filePaths.Remove(filePath);
MidiFileRemoved?.Invoke(filePath);
}
///
/// Removes all registered MIDI files, permanently.
///
/// Raises
public void RemoveAllMidiFiles()
{
foreach (var path in _filePaths)
{
DeleteMidiFile(path);
}
_filePaths.Clear();
MidiFilesReset?.Invoke();
}
///
/// Clears and reloads the entire MIDI library.
///
public void ReloadLibrary()
{
_filePaths.Clear();
if (!_resManager.UserData.IsDir(UserMidiDirectory))
return;
foreach (var path in _resManager.UserData.DirectoryEntries(UserMidiDirectory))
{
var filePath = new ResPath(UserMidiDirectory + path);
if (!filePath.Extension.Equals("midi") && !filePath.Extension.Equals("mid"))
continue;
_filePaths.Add(new ResPath(path));
}
MidiFilesReset?.Invoke();
}
private void DeleteMidiFile(ResPath filePath)
{
var path = (UserMidiDirectory / filePath).Clean();
_resManager.UserData.Delete(path);
}
private void EnsureMidiDirectoryExists()
{
if (!_resManager.UserData.Exists(UserMidiDirectory))
_resManager.UserData.CreateDir(UserMidiDirectory);
}
}