mirror of
https://github.com/Royce551/FRESHMusicPlayer-Core.git
synced 2025-01-22 10:51:56 -05:00
Increase XMLDoc coverage
This commit is contained in:
parent
98f6943ff4
commit
e6de05f971
6 changed files with 262 additions and 4 deletions
|
@ -8,7 +8,11 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace FRESHMusicPlayer.Backends
|
||||
{
|
||||
static class AudioBackendFactory
|
||||
/// <summary>
|
||||
/// A lower level class for directly getting audio backends.
|
||||
/// You should probably use the Player class unless there's a reason you need more control.
|
||||
/// </summary>
|
||||
public static class AudioBackendFactory
|
||||
{
|
||||
private readonly static ContainerConfiguration config = new ContainerConfiguration();
|
||||
private readonly static CompositionHost container;
|
||||
|
@ -36,6 +40,10 @@ namespace FRESHMusicPlayer.Backends
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a directory where FMP will search for audio backends
|
||||
/// </summary>
|
||||
/// <param name="path">The file path of the directory</param>
|
||||
public static void AddDirectory(string path)
|
||||
{
|
||||
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
||||
|
@ -51,6 +59,12 @@ namespace FRESHMusicPlayer.Backends
|
|||
container = config.CreateContainer();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queries the audio backend system for the most appropiate backend for the supplied path
|
||||
/// </summary>
|
||||
/// <param name="filename">The file path to play</param>
|
||||
/// <returns>The appropiate backend</returns>
|
||||
/// <exception cref="Exception">Thrown if no backend could be found</exception>
|
||||
public static async Task<IAudioBackend> CreateAndLoadBackendAsync(string filename)
|
||||
{
|
||||
var problems = new List<(BackendLoadResult, Exception)>();
|
||||
|
|
|
@ -6,32 +6,51 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace FRESHMusicPlayer.Backends
|
||||
{
|
||||
/// <summary>
|
||||
/// A metadata provider that uses ATL to get metadata for most audio formats
|
||||
/// </summary>
|
||||
public class FileMetadataProvider : IMetadataProvider
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string Title => ATLTrack.Title;
|
||||
// for mp3s, ATL still uses /
|
||||
/// <inheritdoc/>
|
||||
public string[] Artists => ATLTrack.Artist.Split(Settings.DisplayValueSeparator, '/');
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Album => ATLTrack.Album;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public byte[] CoverArt => ATLTrack.EmbeddedPictures.Count != 0 ? ATLTrack.EmbeddedPictures[0].PictureData : null;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string[] Genres => ATLTrack.Genre.Split(Settings.DisplayValueSeparator, '/');
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Year => ATLTrack.Year;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int TrackNumber => ATLTrack.TrackNumber;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int TrackTotal => ATLTrack.TrackTotal;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int DiscNumber => ATLTrack.DiscNumber;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int DiscTotal => ATLTrack.DiscTotal;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Length => ATLTrack.Duration;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Track ATLTrack { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets metadata for the supplied file path
|
||||
/// </summary>
|
||||
/// <param name="path">The file path to query metadata for</param>
|
||||
public FileMetadataProvider(string path) => ATLTrack = new Track(path);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,42 +6,127 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace FRESHMusicPlayer.Backends
|
||||
{
|
||||
/// <summary>
|
||||
/// A wrapper for some type of audio library for playing audio
|
||||
/// </summary>
|
||||
public interface IAudioBackend : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Loads the track and gets the backend ready for playback
|
||||
/// </summary>
|
||||
/// <param name="file">File path of the track to be played</param>
|
||||
/// <returns>The result of the load attempt</returns>
|
||||
Task<BackendLoadResult> LoadSongAsync(string file);
|
||||
/// <summary>
|
||||
/// Gets metadata for the given file path
|
||||
/// </summary>
|
||||
/// <param name="file">File path of the track to query metadata for</param>
|
||||
/// <returns>The metadata</returns>
|
||||
Task<IMetadataProvider> GetMetadataAsync(string file);
|
||||
/// <summary>
|
||||
/// Begins playback. If paused, begins playback again
|
||||
/// </summary>
|
||||
void Play();
|
||||
/// <summary>
|
||||
/// Pauses playback but keeps the backend ready to continue
|
||||
/// </summary>
|
||||
void Pause();
|
||||
|
||||
/// <summary>
|
||||
/// The current playhead position in the track
|
||||
/// </summary>
|
||||
TimeSpan CurrentTime { get; set; }
|
||||
/// <summary>
|
||||
/// The total length of the track
|
||||
/// </summary>
|
||||
TimeSpan TotalTime { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The current playback volume, from 0 to 1
|
||||
/// </summary>
|
||||
float Volume { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Raised when playback stops
|
||||
/// </summary>
|
||||
event EventHandler<EventArgs> OnPlaybackStopped;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Should be populated with info about the track the backend is playing
|
||||
/// </summary>
|
||||
public interface IMetadataProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Title of the track
|
||||
/// </summary>
|
||||
string Title { get; }
|
||||
/// <summary>
|
||||
/// Artists of the track
|
||||
/// </summary>
|
||||
string[] Artists { get; }
|
||||
/// <summary>
|
||||
/// The album the track comes from
|
||||
/// </summary>
|
||||
string Album { get; }
|
||||
/// <summary>
|
||||
/// Binary image data for the, ideally, front cover of the album
|
||||
/// </summary>
|
||||
byte[] CoverArt { get; }
|
||||
/// <summary>
|
||||
/// Genres of the track
|
||||
/// </summary>
|
||||
string[] Genres { get; }
|
||||
/// <summary>
|
||||
/// Year the track was made. If not available, 0
|
||||
/// </summary>
|
||||
int Year { get; }
|
||||
/// <summary>
|
||||
/// Track's track number. If not available, 0
|
||||
/// </summary>
|
||||
int TrackNumber { get; }
|
||||
/// <summary>
|
||||
/// Total number of tracks in the album the track is in. If not available, 0
|
||||
/// </summary>
|
||||
int TrackTotal { get; }
|
||||
/// <summary>
|
||||
/// Disc number of the album the track is in. If not available, 0
|
||||
/// </summary>
|
||||
int DiscNumber { get; }
|
||||
/// <summary>
|
||||
/// Total number of discs in the album the track is in. If not available, 0
|
||||
/// </summary>
|
||||
int DiscTotal { get; }
|
||||
/// <summary>
|
||||
/// The length of the track in seconds
|
||||
/// </summary>
|
||||
int Length { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The result of a backend load attempt
|
||||
/// </summary>
|
||||
public enum BackendLoadResult
|
||||
{
|
||||
/// <summary>
|
||||
/// The backend loaded successfully and is really to start playing!
|
||||
/// </summary>
|
||||
OK,
|
||||
/// <summary>
|
||||
/// The backend does not support the kind of file given
|
||||
/// </summary>
|
||||
NotSupported,
|
||||
/// <summary>
|
||||
/// An invalid file was given
|
||||
/// </summary>
|
||||
Invalid,
|
||||
/// <summary>
|
||||
/// There is something wrong with the file given
|
||||
/// </summary>
|
||||
Corrupt,
|
||||
/// <summary>
|
||||
/// Something else went wrong
|
||||
/// </summary>
|
||||
UnknownError
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,17 +8,47 @@ using System.Text;
|
|||
|
||||
namespace FRESHMusicPlayer
|
||||
{
|
||||
/// <summary>
|
||||
/// Wrapper over LiteDB for interacting with the FMP library
|
||||
/// </summary>
|
||||
public class Library
|
||||
{
|
||||
/// <summary>
|
||||
/// The actual LiteDB connection, for things that can't be done with the methods here
|
||||
/// </summary>
|
||||
public LiteDatabase Database { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new library
|
||||
/// </summary>
|
||||
/// <param name="library">The actual LiteDB connection</param>
|
||||
public Library(LiteDatabase library)
|
||||
{
|
||||
Database = library;
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets all tracks in the library
|
||||
/// </summary>
|
||||
/// <param name="filter">Property of DatabaseTrack to order by</param>
|
||||
/// <returns>All the tracks in the library</returns>
|
||||
public List<DatabaseTrack> Read(string filter = "Title") => Database.GetCollection<DatabaseTrack>("tracks").Query().OrderBy(filter).ToList();
|
||||
/// <summary>
|
||||
/// Gets all tracks for the given artist
|
||||
/// </summary>
|
||||
/// <param name="artist">The artist to get tracks for</param>
|
||||
/// <returns>All the tracks for the artist</returns>
|
||||
public List<DatabaseTrack> ReadTracksForArtist(string artist) => Database.GetCollection<DatabaseTrack>("tracks").Query().Where(x => x.Artist == artist).OrderBy("Title").ToList();
|
||||
/// <summary>
|
||||
/// Gets all tracks for the given album
|
||||
/// </summary>
|
||||
/// <param name="album">The artist to get tracks for</param>
|
||||
/// <returns>All the tracks for the album</returns>
|
||||
public List<DatabaseTrack> ReadTracksForAlbum(string album) => Database.GetCollection<DatabaseTrack>("tracks").Query().Where(x => x.Album == album).OrderBy("TrackNumber").ToList();
|
||||
/// <summary>
|
||||
/// Gets all tracks for the given playlist. This must be Task.Run()'d due to a quirk that will be fixed next major release
|
||||
/// </summary>
|
||||
/// <param name="playlist">The artist to get tracks for</param>
|
||||
/// <returns>All the tracks for the playlist</returns>
|
||||
public List<DatabaseTrack> ReadTracksForPlaylist(string playlist)
|
||||
{
|
||||
var x = Database.GetCollection<DatabasePlaylist>("playlists").FindOne(y => y.Name == playlist);
|
||||
|
@ -26,6 +56,11 @@ namespace FRESHMusicPlayer
|
|||
foreach (string path in x.Tracks) z.Add(GetFallbackTrack(path));
|
||||
return z;
|
||||
}
|
||||
/// <summary>
|
||||
/// Adds a track to a playlist
|
||||
/// </summary>
|
||||
/// <param name="playlist">The playlist</param>
|
||||
/// <param name="path">The file path to add</param>
|
||||
public virtual void AddTrackToPlaylist(string playlist, string path)
|
||||
{
|
||||
var x = Database.GetCollection<DatabasePlaylist>("playlists").FindOne(y => y.Name == playlist);
|
||||
|
@ -40,12 +75,23 @@ namespace FRESHMusicPlayer
|
|||
Database.GetCollection<DatabasePlaylist>("playlists").Update(x);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes a track from a playlist
|
||||
/// </summary>
|
||||
/// <param name="playlist">The playlist</param>
|
||||
/// <param name="path">The file path to remove</param>
|
||||
public virtual void RemoveTrackFromPlaylist(string playlist, string path)
|
||||
{
|
||||
var x = Database.GetCollection<DatabasePlaylist>("playlists").FindOne(y => y.Name == playlist);
|
||||
x.Tracks.Remove(path);
|
||||
Database.GetCollection<DatabasePlaylist>("playlists").Update(x);
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a new playlist
|
||||
/// </summary>
|
||||
/// <param name="playlist">The name of the playlist</param>
|
||||
/// <param name="path">An optional track to start the playlist off with</param>
|
||||
/// <returns>The created playlist</returns>
|
||||
public virtual DatabasePlaylist CreatePlaylist(string playlist, string path = null)
|
||||
{
|
||||
var newplaylist = new DatabasePlaylist
|
||||
|
@ -59,7 +105,15 @@ namespace FRESHMusicPlayer
|
|||
Database.GetCollection<DatabasePlaylist>("playlists").Insert(newplaylist);
|
||||
return newplaylist;
|
||||
}
|
||||
/// <summary>
|
||||
/// Deletes a playlist
|
||||
/// </summary>
|
||||
/// <param name="playlist">The name of the playlist to delete</param>
|
||||
public virtual void DeletePlaylist(string playlist) => Database.GetCollection<DatabasePlaylist>("playlists").DeleteMany(x => x.Name == playlist);
|
||||
/// <summary>
|
||||
/// Imports some tracks to the library
|
||||
/// </summary>
|
||||
/// <param name="tracks">The file paths to import</param>
|
||||
public virtual void Import(string[] tracks)
|
||||
{
|
||||
var stufftoinsert = new List<DatabaseTrack>();
|
||||
|
@ -72,6 +126,10 @@ namespace FRESHMusicPlayer
|
|||
}
|
||||
Database.GetCollection<DatabaseTrack>("tracks").InsertBulk(stufftoinsert);
|
||||
}
|
||||
/// <summary>
|
||||
/// Imports some tracks to the library
|
||||
/// </summary>
|
||||
/// <param name="tracks">The file paths to import</param>
|
||||
public virtual void Import(List<string> tracks)
|
||||
{
|
||||
var stufftoinsert = new List<DatabaseTrack>();
|
||||
|
@ -82,21 +140,39 @@ namespace FRESHMusicPlayer
|
|||
}
|
||||
Database.GetCollection<DatabaseTrack>("tracks").InsertBulk(stufftoinsert);
|
||||
}
|
||||
/// <summary>
|
||||
/// Imports a track to the library
|
||||
/// </summary>
|
||||
/// <param name="path">The file path to import</param>
|
||||
public virtual void Import(string path)
|
||||
{
|
||||
var track = new Track(path);
|
||||
Database.GetCollection<DatabaseTrack>("tracks")
|
||||
.Insert(new DatabaseTrack { Title = track.Title, Artist = track.Artist, Album = track.Album, Path = track.Path, TrackNumber = track.TrackNumber, Length = track.Duration });
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes a track from the library
|
||||
/// </summary>
|
||||
/// <param name="path">The file path to remove</param>
|
||||
public virtual void Remove(string path)
|
||||
{
|
||||
Database.GetCollection<DatabaseTrack>("tracks").DeleteMany(x => x.Path == path);
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the entire library
|
||||
/// </summary>
|
||||
/// <param name="nukePlaylists">Whether to also clear playlists</param>
|
||||
public virtual void Nuke(bool nukePlaylists = true)
|
||||
{
|
||||
Database.GetCollection<DatabaseTrack>("tracks").DeleteAll();
|
||||
if (nukePlaylists) Database.GetCollection<DatabasePlaylist>("playlists").DeleteAll();
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets a DatabaseTrack for the given file path. Will try getting from the library system first (fast), before
|
||||
/// falling back to the audio backend system, then finally the default ATL handling
|
||||
/// </summary>
|
||||
/// <param name="path">The file path</param>
|
||||
/// <returns>The track</returns>
|
||||
public DatabaseTrack GetFallbackTrack(string path)
|
||||
{
|
||||
var dbTrack = Database.GetCollection<DatabaseTrack>("tracks").FindOne(x => path == x.Path);
|
||||
|
@ -118,19 +194,52 @@ namespace FRESHMusicPlayer
|
|||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Representation of a track in the database
|
||||
/// </summary>
|
||||
public class DatabaseTrack
|
||||
{
|
||||
/// <summary>
|
||||
/// The file path
|
||||
/// </summary>
|
||||
public string Path { get; set; }
|
||||
/// <summary>
|
||||
/// Title of the track
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
/// <summary>
|
||||
/// Semicolon separated list of artists
|
||||
/// </summary>
|
||||
public string Artist { get; set; }
|
||||
/// <summary>
|
||||
/// Album of the track
|
||||
/// </summary>
|
||||
public string Album { get; set; }
|
||||
/// <summary>
|
||||
/// The track's track number. If not available, set to 0
|
||||
/// </summary>
|
||||
public int TrackNumber { get; set; }
|
||||
/// <summary>
|
||||
/// The length of the track in seconds
|
||||
/// </summary>
|
||||
public int Length { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Representation of a playlist in the database
|
||||
/// </summary>
|
||||
public class DatabasePlaylist
|
||||
{
|
||||
/// <summary>
|
||||
/// The ID of the playlist
|
||||
/// </summary>
|
||||
public int DatabasePlaylistID { get; set; }
|
||||
/// <summary>
|
||||
/// The playlist's name
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
/// <summary>
|
||||
/// All tracks in the playlist
|
||||
/// </summary>
|
||||
public List<string> Tracks { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,11 +6,25 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace FRESHMusicPlayer
|
||||
{
|
||||
/// <summary>
|
||||
/// Playback exception args
|
||||
/// </summary>
|
||||
public class PlaybackExceptionEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The actual exception
|
||||
/// </summary>
|
||||
public Exception Exception { get; }
|
||||
/// <summary>
|
||||
/// A nicely formatted version of the exception for display purposes
|
||||
/// </summary>
|
||||
public string Details { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructs new playback exception args
|
||||
/// </summary>
|
||||
/// <param name="exception">The actual exception</param>
|
||||
/// <param name="details">A nicely formatted version of the exception for display purposes</param>
|
||||
public PlaybackExceptionEventArgs(Exception exception, string details)
|
||||
{
|
||||
Exception = exception;
|
||||
|
|
|
@ -8,12 +8,19 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace FRESHMusicPlayer
|
||||
{
|
||||
/// <summary>
|
||||
/// The main class for playing audio using FMP Core.
|
||||
/// Intended to be constructed once and used for the entire app's lifetime
|
||||
/// </summary>
|
||||
public class Player
|
||||
{
|
||||
/// <summary>
|
||||
/// The current backend the Player is using for audio playback
|
||||
/// </summary>
|
||||
public IAudioBackend CurrentBackend { get; private set; }
|
||||
/// <summary>
|
||||
/// Metadata for the current track the Player is playing
|
||||
/// </summary>
|
||||
public IMetadataProvider Metadata { get; private set; }
|
||||
/// <summary>
|
||||
/// The current playback position./>
|
||||
|
@ -44,6 +51,9 @@ namespace FRESHMusicPlayer
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the Player is in a loading state - You cannot start playing a new track while this is true.
|
||||
/// </summary>
|
||||
public bool IsLoading { get; private set; } = false;
|
||||
/// <summary>
|
||||
/// The current path the Player is playing. Keep in mind that this may not necessarily be a file. For example, it could be the
|
||||
|
@ -60,8 +70,14 @@ namespace FRESHMusicPlayer
|
|||
/// </summary>
|
||||
public bool Paused { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The play queue
|
||||
/// </summary>
|
||||
public PlayQueue Queue { get; set; } = new PlayQueue();
|
||||
|
||||
/// <summary>
|
||||
/// Raised whenever the player is beginning to load a track, before SongChanged is raised
|
||||
/// </summary>
|
||||
public event EventHandler SongLoading;
|
||||
/// <summary>
|
||||
/// Raised whenever a new track is being played.
|
||||
|
@ -130,9 +146,10 @@ namespace FRESHMusicPlayer
|
|||
await PlayAsync();
|
||||
}
|
||||
/// <summary>
|
||||
/// Starts playing the Queue. In order to play a track, you must first add it to the Queue using <see cref="AddQueue(string)"/>.
|
||||
/// Starts playing the Queue. In order to play a track, you must first add it to the Queue.
|
||||
/// </summary>
|
||||
/// <param name="repeat">If true, avoids dequeuing the next track. Not to be used for anything other than the player.</param>
|
||||
/// <param name="loadMetadata">Whether to load metadata for the track</param>
|
||||
public async Task PlayAsync(bool repeat = false, bool loadMetadata = true)
|
||||
{
|
||||
if (IsLoading) return;
|
||||
|
@ -198,7 +215,7 @@ namespace FRESHMusicPlayer
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pauses playback without disposing. Can later be resumed with <see cref="ResumeMusic()"/>.
|
||||
/// Pauses playback without disposing. Can later be resumed with <see cref="Resume()"/>.
|
||||
/// </summary>
|
||||
public void Pause()
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue