mirror of
https://github.com/space-syndicate/space-station-14.git
synced 2026-10-09 18:31:17 +03:00
201 lines
6.6 KiB
C#
201 lines
6.6 KiB
C#
using System.IO;
|
|
using System.Threading.Tasks;
|
|
using JetBrains.Annotations;
|
|
using Robust.Shared.ContentPack;
|
|
using Robust.Shared.Utility;
|
|
|
|
namespace Content.Client.Audio.Midi;
|
|
|
|
/// <summary>
|
|
/// Handles storage/management of MIDI files stored inside the user data directory.
|
|
/// </summary>
|
|
[PublicAPI]
|
|
public sealed partial class MidiFileCollectionManager : IPostInjectInit
|
|
{
|
|
/// <summary>
|
|
/// Directory path to use inside UserData for storing MIDIs.
|
|
/// </summary>
|
|
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<ResPath> _filePaths = [];
|
|
|
|
/// <summary>
|
|
/// Raised after a MIDI file has been added to the library. Contains added file path as argument.
|
|
/// </summary>
|
|
public event Action<ResPath>? MidiFileAdded;
|
|
|
|
/// <summary>
|
|
/// Raised after a MIDI file has been removed from the library. Contains removed file path as argument.
|
|
/// </summary>
|
|
public event Action<ResPath>? MidiFileRemoved;
|
|
|
|
/// <summary>
|
|
/// Raised after more than one or two library changes occured at once. (i.e. initial load or when all items deleted)
|
|
/// </summary>
|
|
public event Action? MidiFilesReset;
|
|
|
|
///<inheritdoc cref="IPostInjectInit"/>
|
|
public void PostInject()
|
|
{
|
|
EnsureMidiDirectoryExists();
|
|
ReloadLibrary();
|
|
_sawmill = _logManager.GetSawmill(SawmillCategory);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the binary content of the given MIDI file.
|
|
/// </summary>
|
|
/// <param name="filePath">MIDI file path to get.</param>
|
|
/// <returns>MIDI binary as a byte array or an empty byte array if the file doesn't exist.</returns>
|
|
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 [];
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns an enumeration of all available MIDI files.
|
|
/// </summary>
|
|
/// <returns>An enumeration of MIDI file paths.</returns>
|
|
public IEnumerable<ResPath> GetMidiFiles()
|
|
{
|
|
return _filePaths;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stores the given byte stream with the given file path inside the <see cref="UserMidiDirectory"/> directory.
|
|
/// </summary>
|
|
/// <param name="filePath">File path to write.</param>
|
|
/// <param name="data">Binary data to write.</param>
|
|
/// <remarks>Raises <see cref="MidiFileAdded"/> on success.</remarks>
|
|
public async Task<bool> 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;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stores the given byte array with the given file path inside the <see cref="UserMidiDirectory"/> directory.
|
|
/// </summary>
|
|
/// <param name="filePath">File path to write.</param>
|
|
/// <param name="data">Binary data to write.</param>
|
|
/// <remarks>Raises <see cref="MidiFileAdded"/> on success.</remarks>
|
|
public async Task<bool> AddMidiFile(ResPath filePath, byte[] data)
|
|
{
|
|
return await AddMidiFile(filePath, new MemoryStream(data));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Renames a MIDI file inside the library.
|
|
/// </summary>
|
|
/// <param name="oldPath">Current file path</param>
|
|
/// <param name="newPath">New file path</param>
|
|
/// <remarks>Raises <see cref="MidiFileRemoved"/> and <see cref="MidiFileAdded"/> on success.</remarks>
|
|
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;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Permanently removes the given MIDI file if it exists inside <see cref="UserMidiDirectory"/>.
|
|
/// </summary>
|
|
/// <param name="filePath">File path to remove.</param>
|
|
/// <remarks>Raises <see cref="MidiFileRemoved"/></remarks>
|
|
public void RemoveMidiFile(ResPath filePath)
|
|
{
|
|
DeleteMidiFile(filePath);
|
|
_filePaths.Remove(filePath);
|
|
MidiFileRemoved?.Invoke(filePath);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes all registered MIDI files, permanently.
|
|
/// </summary>
|
|
/// <remarks>Raises <see cref="MidiFilesReset"/></remarks>
|
|
public void RemoveAllMidiFiles()
|
|
{
|
|
foreach (var path in _filePaths)
|
|
{
|
|
DeleteMidiFile(path);
|
|
}
|
|
|
|
_filePaths.Clear();
|
|
MidiFilesReset?.Invoke();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clears and reloads the entire MIDI library.
|
|
/// </summary>
|
|
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);
|
|
}
|
|
}
|