mirror of
https://github.com/Royce551/FRESHMusicPlayer-Core.git
synced 2025-01-22 10:51:56 -05:00
commit
f0f522c331
17 changed files with 679 additions and 349 deletions
|
@ -3,11 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
|||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30114.105
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FRESHMusicPlayer.Core", "FRESHMusicPlayer.Player\FRESHMusicPlayer.Core.csproj", "{FFE8EAFD-7FAA-4503-9364-2643821A2BC8}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FRESHMusicPlayer.Core", "FRESHMusicPlayer.Player\FRESHMusicPlayer.Core.csproj", "{FFE8EAFD-7FAA-4503-9364-2643821A2BC8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinformsTest", "WinformsTest\WinformsTest.csproj", "{AA375910-6E80-4570-9663-8EA13238192A}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinformsTest", "WinformsTest\WinformsTest.csproj", "{AA375910-6E80-4570-9663-8EA13238192A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GtkSharpTest", "GtkSharpTest\GtkSharpTest.csproj", "{8FE8EBF4-7E03-47B5-86AF-0DEA77260F24}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GtkSharpTest", "GtkSharpTest\GtkSharpTest.csproj", "{8FE8EBF4-7E03-47B5-86AF-0DEA77260F24}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FmpCdLibBackend", "FmpCdLibBackend\FmpCdLibBackend.csproj", "{31D77A1D-F161-42E8-826E-3E27E6566B28}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
@ -27,6 +29,10 @@ Global
|
|||
{8FE8EBF4-7E03-47B5-86AF-0DEA77260F24}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8FE8EBF4-7E03-47B5-86AF-0DEA77260F24}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8FE8EBF4-7E03-47B5-86AF-0DEA77260F24}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{31D77A1D-F161-42E8-826E-3E27E6566B28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{31D77A1D-F161-42E8-826E-3E27E6566B28}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{31D77A1D-F161-42E8-826E-3E27E6566B28}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{31D77A1D-F161-42E8-826E-3E27E6566B28}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -12,8 +12,6 @@ namespace FRESHMusicPlayer.Backends
|
|||
private static ContainerConfiguration config = new ContainerConfiguration();
|
||||
private static CompositionHost container;
|
||||
|
||||
private static List<string> directories = new List<string>();
|
||||
|
||||
private static IEnumerable<Assembly> LoadAssemblies(IEnumerable<string> paths)
|
||||
{
|
||||
foreach (var file in paths)
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>FRESHMusicPlayer.Player</RootNamespace>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<PackageTags>audio music-player</PackageTags>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release+Package|AnyCPU' ">
|
||||
<Optimize>true</Optimize>
|
||||
|
@ -18,13 +19,11 @@
|
|||
<Compile Remove="Handlers\InternetHandler.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DiscordRichPresence" Version="1.0.150" />
|
||||
<PackageReference Include="LiteDB" Version="5.0.9" />
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
<PackageReference Include="NAudio" Version="1.10.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="System.Composition" Version="1.4.1" />
|
||||
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
|
||||
<PackageReference Include="z440.atl.core" Version="3.7.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -1,144 +0,0 @@
|
|||
using FRESHMusicPlayer.Utilities;
|
||||
using Lite = LiteDB;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace FRESHMusicPlayer.Handlers
|
||||
{
|
||||
public static class DatabaseHandler
|
||||
{
|
||||
public static readonly int DatabaseVersion = 1;
|
||||
public static readonly string DatabasePath;
|
||||
static DatabaseHandler()
|
||||
{
|
||||
DatabasePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "FRESHMusicPlayer");
|
||||
}
|
||||
#region v1
|
||||
/// <summary>
|
||||
/// Returns all of the tracks in the database.
|
||||
/// </summary>
|
||||
/// <returns>A list of file paths in the database.</returns>
|
||||
public static List<string> ReadSongs()
|
||||
{
|
||||
if (!File.Exists(DatabasePath + "\\database.json"))
|
||||
{
|
||||
Directory.CreateDirectory(DatabasePath);
|
||||
File.WriteAllText(DatabasePath + "\\database.json", $"{{\"Version\":{DatabaseVersion},\"Songs\":[]}}");
|
||||
}
|
||||
using (var file = File.OpenText(DatabasePath + "\\database.json")) // Read json file
|
||||
{
|
||||
var serializer = new JsonSerializer();
|
||||
var database = (DatabaseFormat)serializer.Deserialize(file, typeof(DatabaseFormat));
|
||||
return database.Songs;
|
||||
}
|
||||
}
|
||||
|
||||
public static void ImportSong(string filepath)
|
||||
{
|
||||
var database = ReadSongs();
|
||||
|
||||
database.Add(filepath); // Add the new song in
|
||||
var format = new DatabaseFormat
|
||||
{
|
||||
Version = 1,
|
||||
Songs = new List<string>()
|
||||
};
|
||||
format.Songs = database;
|
||||
|
||||
using (var file = File.CreateText(DatabasePath + "\\database.json"))
|
||||
{
|
||||
var serializer = new JsonSerializer();
|
||||
serializer.Serialize(file, format);
|
||||
}
|
||||
|
||||
}
|
||||
public static void ImportSong(string[] filepath)
|
||||
{
|
||||
var database = ReadSongs();
|
||||
|
||||
database.AddRange(filepath);
|
||||
var format = new DatabaseFormat
|
||||
{
|
||||
Version = 1,
|
||||
Songs = new List<string>()
|
||||
};
|
||||
format.Songs = database;
|
||||
|
||||
using (var file = File.CreateText(DatabasePath + "\\database.json"))
|
||||
{
|
||||
var serializer = new JsonSerializer();
|
||||
serializer.Serialize(file, format);
|
||||
}
|
||||
|
||||
}
|
||||
public static void ImportSong(List<string> filepath)
|
||||
{
|
||||
var database = ReadSongs();
|
||||
|
||||
database.AddRange(filepath);
|
||||
var format = new DatabaseFormat
|
||||
{
|
||||
Version = 1,
|
||||
Songs = new List<string>()
|
||||
};
|
||||
format.Songs = database;
|
||||
|
||||
using (var file = File.CreateText(DatabasePath + "\\database.json"))
|
||||
{
|
||||
var serializer = new JsonSerializer();
|
||||
serializer.Serialize(file, format);
|
||||
}
|
||||
|
||||
}
|
||||
public static void ImportSong(IList<string> filepath)
|
||||
{
|
||||
var database = ReadSongs();
|
||||
|
||||
database.AddRange(filepath);
|
||||
var format = new DatabaseFormat
|
||||
{
|
||||
Version = 1,
|
||||
Songs = new List<string>()
|
||||
};
|
||||
format.Songs = database;
|
||||
|
||||
using (var file = File.CreateText(DatabasePath + "\\database.json"))
|
||||
{
|
||||
var serializer = new JsonSerializer();
|
||||
serializer.Serialize(file, format);
|
||||
}
|
||||
|
||||
}
|
||||
public static void DeleteSong(string filepath)
|
||||
{
|
||||
var database = ReadSongs();
|
||||
database.Remove(filepath);
|
||||
var format = new DatabaseFormat
|
||||
{
|
||||
Version = 1,
|
||||
Songs = database
|
||||
};
|
||||
|
||||
|
||||
using (var file = File.CreateText(DatabasePath + "\\database.json"))
|
||||
{
|
||||
var serializer = new JsonSerializer();
|
||||
serializer.Serialize(file, format);
|
||||
}
|
||||
}
|
||||
public static void ClearLibrary()
|
||||
{
|
||||
if (File.Exists(DatabasePath + "\\database.json"))
|
||||
{
|
||||
File.Delete(DatabasePath + "\\database.json");
|
||||
File.WriteAllText(DatabasePath + "\\database.json", @"{""Version"":1,""Songs"":[]}");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -8,6 +8,13 @@ namespace FRESHMusicPlayer.Handlers
|
|||
{
|
||||
public class PlaybackExceptionEventArgs : EventArgs
|
||||
{
|
||||
public string Details { get; set; }
|
||||
public Exception Exception { get; }
|
||||
public string Details { get; }
|
||||
|
||||
public PlaybackExceptionEventArgs(Exception exception, string details)
|
||||
{
|
||||
Exception = exception;
|
||||
Details = details;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
using ATL;
|
||||
using LiteDB;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace FRESHMusicPlayer.Handlers
|
||||
{
|
||||
public class Library
|
||||
{
|
||||
public LiteDatabase Database { get; private set; }
|
||||
|
||||
public Library(LiteDatabase library)
|
||||
{
|
||||
Database = library;
|
||||
}
|
||||
public List<DatabaseTrack> Read(string filter = "Title") => Database.GetCollection<DatabaseTrack>("tracks").Query().OrderBy(filter).ToList();
|
||||
public List<DatabaseTrack> ReadTracksForArtist(string artist) => Database.GetCollection<DatabaseTrack>("tracks").Query().Where(x => x.Artist == artist).OrderBy("Title").ToList();
|
||||
public List<DatabaseTrack> ReadTracksForAlbum(string album) => Database.GetCollection<DatabaseTrack>("tracks").Query().Where(x => x.Album == album).OrderBy("TrackNumber").ToList();
|
||||
public List<DatabaseTrack> ReadTracksForPlaylist(string playlist)
|
||||
{
|
||||
var x = Database.GetCollection<DatabasePlaylist>("playlists").FindOne(y => y.Name == playlist);
|
||||
var z = new List<DatabaseTrack>();
|
||||
foreach (string path in x.Tracks) z.Add(GetFallbackTrack(path));
|
||||
return z;
|
||||
}
|
||||
public void AddTrackToPlaylist(string playlist, string path)
|
||||
{
|
||||
var x = Database.GetCollection<DatabasePlaylist>("playlists").FindOne(y => y.Name == playlist);
|
||||
if (Database.GetCollection<DatabasePlaylist>("playlists").FindOne(y => y.Name == playlist) is null)
|
||||
{
|
||||
x = CreatePlaylist(playlist, path);
|
||||
x.Tracks.Add(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
x.Tracks.Add(path);
|
||||
Database.GetCollection<DatabasePlaylist>("playlists").Update(x);
|
||||
}
|
||||
}
|
||||
public 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);
|
||||
}
|
||||
public DatabasePlaylist CreatePlaylist(string playlist, string path = null)
|
||||
{
|
||||
var newplaylist = new DatabasePlaylist
|
||||
{
|
||||
Name = playlist,
|
||||
Tracks = new List<string>()
|
||||
};
|
||||
if (Database.GetCollection<DatabasePlaylist>("playlists").Count() == 0) newplaylist.DatabasePlaylistID = 0;
|
||||
else newplaylist.DatabasePlaylistID = Database.GetCollection<DatabasePlaylist>("playlists").Query().ToList().Last().DatabasePlaylistID + 1;
|
||||
if (path != null) newplaylist.Tracks.Add(path);
|
||||
Database.GetCollection<DatabasePlaylist>("playlists").Insert(newplaylist);
|
||||
return newplaylist;
|
||||
}
|
||||
public void DeletePlaylist(string playlist) => Database.GetCollection<DatabasePlaylist>("playlists").DeleteMany(x => x.Name == playlist);
|
||||
public void Import(string[] tracks)
|
||||
{
|
||||
var stufftoinsert = new List<DatabaseTrack>();
|
||||
int count = 0;
|
||||
foreach (string y in tracks)
|
||||
{
|
||||
var track = new Track(y);
|
||||
stufftoinsert.Add(new DatabaseTrack { Title = track.Title, Artist = track.Artist, Album = track.Album, Path = track.Path, TrackNumber = track.TrackNumber, Length = track.Duration });
|
||||
count++;
|
||||
}
|
||||
Database.GetCollection<DatabaseTrack>("tracks").InsertBulk(stufftoinsert);
|
||||
}
|
||||
public void Import(List<string> tracks)
|
||||
{
|
||||
var stufftoinsert = new List<DatabaseTrack>();
|
||||
foreach (string y in tracks)
|
||||
{
|
||||
var track = new Track(y);
|
||||
stufftoinsert.Add(new DatabaseTrack { Title = track.Title, Artist = track.Artist, Album = track.Album, Path = track.Path, TrackNumber = track.TrackNumber, Length = track.Duration });
|
||||
}
|
||||
Database.GetCollection<DatabaseTrack>("tracks").InsertBulk(stufftoinsert);
|
||||
}
|
||||
public 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 });
|
||||
}
|
||||
public void Remove(string path)
|
||||
{
|
||||
Database.GetCollection<DatabaseTrack>("tracks").DeleteMany(x => x.Path == path);
|
||||
}
|
||||
public virtual void Nuke(bool nukePlaylists = true)
|
||||
{
|
||||
Database.GetCollection<DatabaseTrack>("tracks").DeleteAll();
|
||||
if (nukePlaylists) Database.GetCollection<DatabasePlaylist>("playlists").DeleteAll();
|
||||
}
|
||||
public DatabaseTrack GetFallbackTrack(string path)
|
||||
{
|
||||
var dbTrack = Database.GetCollection<DatabaseTrack>("tracks").FindOne(x => path == x.Path);
|
||||
if (dbTrack != null) return dbTrack;
|
||||
else
|
||||
{
|
||||
var track = new Track(path);
|
||||
return new DatabaseTrack { Artist = track.Artist, Title = track.Title, Album = track.Album, Length = track.Duration, Path = path, TrackNumber = track.TrackNumber };
|
||||
}
|
||||
}
|
||||
}
|
||||
public class DatabaseTrack
|
||||
{
|
||||
public string Path { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Artist { get; set; }
|
||||
public string Album { get; set; }
|
||||
public int TrackNumber { get; set; }
|
||||
public int Length { get; set; }
|
||||
}
|
||||
public class DatabasePlaylist
|
||||
{
|
||||
public int DatabasePlaylistID { get; set; }
|
||||
public string Name { get; set; }
|
||||
public List<string> Tracks { get; set; }
|
||||
}
|
||||
}
|
173
FRESHMusicPlayer.Player/FRESHMusicPlayer.Player/PlayQueue.cs
Normal file
173
FRESHMusicPlayer.Player/FRESHMusicPlayer.Player/PlayQueue.cs
Normal file
|
@ -0,0 +1,173 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace FRESHMusicPlayer
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the player's queue.
|
||||
/// </summary>
|
||||
public class PlayQueue
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the current queue. This is settable for situations where there's no method for what you want to do.
|
||||
/// Use the methods in this class for managing the queue so that events can fire and stuff doesn't break in the future.
|
||||
/// </summary>
|
||||
public List<string> Queue
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Shuffle)
|
||||
return shuffledQueue;
|
||||
else return queue;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (Shuffle)
|
||||
{
|
||||
shuffledQueue = value;
|
||||
ShuffleQueue();
|
||||
}
|
||||
queue = value;
|
||||
}
|
||||
}
|
||||
|
||||
private bool shuffle = false;
|
||||
/// <summary>
|
||||
/// Gets or sets whether the queue should be shuffled.
|
||||
/// </summary>
|
||||
public bool Shuffle
|
||||
{
|
||||
get => shuffle;
|
||||
set
|
||||
{
|
||||
shuffle = value;
|
||||
if (shuffle) shuffledQueue = new List<string>(queue);
|
||||
else shuffledQueue = null;
|
||||
QueueChanged?.Invoke(null, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or sets the current repeat mode.
|
||||
/// </summary>
|
||||
public RepeatMode RepeatMode { get; set; } = RepeatMode.None;
|
||||
/// <summary>
|
||||
/// Gets or sets the index in the queue of the track that the Player is going to play *next*.
|
||||
/// </summary>
|
||||
public int Position { get; set; }
|
||||
/// <summary>
|
||||
/// Fired when the queue changes.
|
||||
/// </summary>
|
||||
public event EventHandler QueueChanged;
|
||||
|
||||
private List<string> queue = new List<string>();
|
||||
private List<string> shuffledQueue;
|
||||
|
||||
private readonly Random rng = new Random();
|
||||
|
||||
/// <summary>
|
||||
/// Adds a track to the queue.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The track to add</param>
|
||||
public void Add(string filePath)
|
||||
{
|
||||
queue.Add(filePath);
|
||||
if (Shuffle)
|
||||
{
|
||||
shuffledQueue.Add(filePath);
|
||||
ShuffleQueue();
|
||||
}
|
||||
QueueChanged?.Invoke(null, EventArgs.Empty);
|
||||
}
|
||||
/// <summary>
|
||||
/// Adds multiple tracks to the queue.
|
||||
/// </summary>
|
||||
/// <param name="filePaths">The tracks to add.</param>
|
||||
public void Add(string[] filePaths)
|
||||
{
|
||||
queue.AddRange(filePaths);
|
||||
if (Shuffle)
|
||||
{
|
||||
shuffledQueue.AddRange(filePaths);
|
||||
ShuffleQueue();
|
||||
}
|
||||
QueueChanged?.Invoke(null, EventArgs.Empty);
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the queue.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
queue.Clear();
|
||||
if (Shuffle)
|
||||
shuffledQueue.Clear();
|
||||
Position = 0;
|
||||
QueueChanged?.Invoke(null, EventArgs.Empty);
|
||||
}
|
||||
/// <summary>
|
||||
/// Shuffles the queue. If <see cref="Shuffle"/> isn't true, this will not do anything.
|
||||
/// </summary>
|
||||
public void ManualShuffle()
|
||||
{
|
||||
if (Shuffle)
|
||||
ShuffleQueue();
|
||||
QueueChanged?.Invoke(null, EventArgs.Empty);
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes a track from the queue.
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the track you want to remove.</param>
|
||||
public void Remove(int index)
|
||||
{
|
||||
if (index <= (Position - 1)) Position--;
|
||||
if (Position < 0) Position = 1;
|
||||
queue.RemoveAt(index);
|
||||
if (Shuffle)
|
||||
shuffledQueue.RemoveAt(index);
|
||||
QueueChanged?.Invoke(null, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private void ShuffleQueue()
|
||||
{
|
||||
var listtosort = new List<string>();
|
||||
var listtoreinsert = new List<string>();
|
||||
var number = 0;
|
||||
foreach (var x in shuffledQueue)
|
||||
{
|
||||
if (Position < number) listtosort.Add(x);
|
||||
else listtoreinsert.Add(x);
|
||||
number++;
|
||||
}
|
||||
|
||||
var n = listtosort.Count;
|
||||
while (n > 1)
|
||||
{
|
||||
n--;
|
||||
var k = rng.Next(n + 1);
|
||||
var value = listtosort[k];
|
||||
listtosort[k] = listtosort[n];
|
||||
listtosort[n] = value;
|
||||
}
|
||||
listtoreinsert.AddRange(listtosort);
|
||||
shuffledQueue = listtoreinsert;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// The way that the queue will be repeated
|
||||
/// </summary>
|
||||
public enum RepeatMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Do not repeat tracks in the queue
|
||||
/// </summary>
|
||||
None,
|
||||
/// <summary>
|
||||
/// Repeat the currently playing track
|
||||
/// </summary>
|
||||
RepeatOne,
|
||||
/// <summary>
|
||||
/// Repeat the entire queue
|
||||
/// </summary>
|
||||
RepeatAll
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using DiscordRPC;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
@ -12,74 +11,77 @@ namespace FRESHMusicPlayer
|
|||
{
|
||||
public class Player
|
||||
{
|
||||
/// <summary>
|
||||
/// The current backend the Player is using for audio playback
|
||||
/// </summary>
|
||||
public IAudioBackend CurrentBackend { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The current playback position./>
|
||||
/// </summary>
|
||||
public TimeSpan CurrentTime { get => CurrentBackend.CurrentTime; set => CurrentBackend.CurrentTime = value; }
|
||||
/// <summary>
|
||||
/// The total length of the current track.
|
||||
/// </summary>
|
||||
public TimeSpan TotalTime { get => CurrentBackend.TotalTime; }
|
||||
/// <summary>
|
||||
/// If true, suppresses an internal event handler. I honestly don't understand how this thing works; just make sure to keep
|
||||
/// setting this to false, or things will explode.
|
||||
/// </summary>
|
||||
public bool AvoidNextQueue { get; set; }
|
||||
public DiscordRpcClient Client { get; set; }
|
||||
|
||||
public float CurrentVolume { get; set; } = 1;
|
||||
public string FilePath { get; set; } = string.Empty;
|
||||
public bool Playing { get; set; }
|
||||
private float volume = 1f;
|
||||
/// <summary>
|
||||
/// The current volume, from 0 to 1.
|
||||
/// </summary>
|
||||
public float Volume
|
||||
{
|
||||
get => volume;
|
||||
set
|
||||
{
|
||||
volume = value;
|
||||
if (FileLoaded)
|
||||
CurrentBackend.Volume = volume;
|
||||
}
|
||||
}
|
||||
/// <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
|
||||
/// URL to a network stream.
|
||||
/// </summary>
|
||||
public string FilePath { get; private set; } = string.Empty;
|
||||
/// <summary>
|
||||
/// Whether the audio backend and file has been loaded and things are ready to go. If you interact with the Player everything
|
||||
/// will explode.
|
||||
/// </summary>
|
||||
public bool FileLoaded { get; set; }
|
||||
/// <summary>
|
||||
/// Whether the Player is paused.
|
||||
/// </summary>
|
||||
public bool Paused { get; set; }
|
||||
|
||||
public bool RepeatOnce { get; set; } = false;
|
||||
public PlayQueue Queue { get; set; } = new PlayQueue();
|
||||
|
||||
public bool Shuffle { get; set; } = false;
|
||||
|
||||
// TODO: ^^ for the two properties above, check if their setters are ever used
|
||||
public List<string> Queue { get; private set; } = new List<string>();
|
||||
public int QueuePosition { get; set; }
|
||||
/// <summary>
|
||||
/// Raised whenever a new track is being played.
|
||||
/// </summary>
|
||||
public event EventHandler SongChanged;
|
||||
/// <summary>
|
||||
/// Raised whenever the player is stopping.
|
||||
/// </summary>
|
||||
public event EventHandler SongStopped;
|
||||
/// <summary>
|
||||
/// Raised whenever an exception is thrown while the Player is loading a file.
|
||||
/// </summary>
|
||||
public event EventHandler<PlaybackExceptionEventArgs> SongException;
|
||||
public event EventHandler QueueChanged;
|
||||
|
||||
#region CoreFMP
|
||||
|
||||
// Queue System
|
||||
/// <summary>
|
||||
/// Adds a track to the <see cref="Queue"/>.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The file path to the track to add.</param>
|
||||
public void AddQueue(string filePath)
|
||||
{
|
||||
Queue.Add(filePath);
|
||||
QueueChanged?.Invoke(null, EventArgs.Empty);
|
||||
}
|
||||
public void AddQueue(string[] filePaths)
|
||||
{
|
||||
Queue.AddRange(filePaths);
|
||||
QueueChanged?.Invoke(null, EventArgs.Empty);
|
||||
}
|
||||
public void ClearQueue()
|
||||
{
|
||||
Queue.Clear();
|
||||
QueuePosition = 0;
|
||||
QueueChanged?.Invoke(null, EventArgs.Empty);
|
||||
}
|
||||
public void ShuffleQueue()
|
||||
{
|
||||
Queue = this.ShuffleQueue(Queue);
|
||||
QueueChanged?.Invoke(null, EventArgs.Empty);
|
||||
}
|
||||
public void RemoveQueue(int index)
|
||||
{
|
||||
Queue.RemoveAt(index);
|
||||
if (index <= (QueuePosition - 1)) QueuePosition--;
|
||||
if (QueuePosition < 0) QueuePosition = 1;
|
||||
QueueChanged?.Invoke(null, EventArgs.Empty);
|
||||
}
|
||||
/// <summary>
|
||||
/// Skips to the previous track in the Queue. If there are no tracks for the player to go back to, nothing will happen.
|
||||
/// </summary>
|
||||
public void PreviousSong()
|
||||
{
|
||||
if (QueuePosition <= 1) return;
|
||||
if (Shuffle) Queue = this.ShuffleQueue(Queue);
|
||||
QueuePosition -= 2;
|
||||
if (Queue.Position <= 1) return;
|
||||
Queue.Position -= 2;
|
||||
PlayMusic();
|
||||
}
|
||||
|
||||
|
@ -90,13 +92,17 @@ namespace FRESHMusicPlayer
|
|||
public void NextSong(bool avoidNext = false)
|
||||
{
|
||||
AvoidNextQueue = avoidNext;
|
||||
if (RepeatOnce) QueuePosition--; // Don't advance Queue, play the same thing again
|
||||
if (Shuffle) Queue = this.ShuffleQueue(Queue);
|
||||
if (Queue.RepeatMode == RepeatMode.RepeatOne) Queue.Position--; // Don't advance Queue, play the same thing again
|
||||
|
||||
if (QueuePosition >= Queue.Count)
|
||||
if (Queue.Position >= Queue.Queue.Count)
|
||||
{
|
||||
if (Queue.RepeatMode == RepeatMode.RepeatAll) // Go back to the first track and play it again
|
||||
{
|
||||
Queue.Position = 0;
|
||||
PlayMusic();
|
||||
return;
|
||||
}
|
||||
Queue.Clear();
|
||||
QueuePosition = 0;
|
||||
StopMusic();
|
||||
return;
|
||||
}
|
||||
|
@ -121,30 +127,38 @@ namespace FRESHMusicPlayer
|
|||
CurrentBackend.CurrentTime = TimeSpan.FromSeconds(seconds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Plays a track. This is equivalent to calling Queue.Add() and then PlayMusic()./>
|
||||
/// </summary>
|
||||
/// <param name="path">The track to play</param>
|
||||
public void PlayMusic(string path)
|
||||
{
|
||||
Queue.Add(path);
|
||||
PlayMusic();
|
||||
}
|
||||
/// <summary>
|
||||
/// Starts playing the Queue. In order to play a track, you must first add it to the Queue using <see cref="AddQueue(string)"/>.
|
||||
/// </summary>
|
||||
/// <param name="repeat">If true, avoids dequeuing the next track. Not to be used for anything other than the player.</param>
|
||||
public void PlayMusic(bool repeat = false)
|
||||
{
|
||||
if (!repeat && Queue.Count != 0)
|
||||
FilePath = Queue[QueuePosition];
|
||||
QueuePosition++;
|
||||
QueueChanged?.Invoke(null, EventArgs.Empty);
|
||||
if (!repeat && Queue.Queue.Count != 0)
|
||||
FilePath = Queue.Queue[Queue.Position];
|
||||
Queue.Position++;
|
||||
void PMusic()
|
||||
{
|
||||
CurrentBackend = AudioBackendFactory.CreateBackend(FilePath);
|
||||
|
||||
CurrentBackend.Play();
|
||||
CurrentBackend.Volume = CurrentVolume;
|
||||
CurrentBackend.Volume = Volume;
|
||||
CurrentBackend.OnPlaybackStopped += OnPlaybackStopped;
|
||||
|
||||
Playing = true;
|
||||
FileLoaded = true;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (Playing != true)
|
||||
if (FileLoaded != true)
|
||||
{
|
||||
PMusic();
|
||||
}
|
||||
|
@ -158,34 +172,34 @@ namespace FRESHMusicPlayer
|
|||
SongChanged?.Invoke(null,
|
||||
EventArgs.Empty); // Now that playback has started without any issues, fire the song changed event.
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
var args = new PlaybackExceptionEventArgs {Details = "That's not a valid file path!"};
|
||||
SongException?.Invoke(null, args);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
var args = new PlaybackExceptionEventArgs {Details = "That's not a valid file path!"};
|
||||
SongException?.Invoke(null, args);
|
||||
}
|
||||
catch (System.Runtime.InteropServices.COMException)
|
||||
{
|
||||
var args = new PlaybackExceptionEventArgs {Details = "This isn't a valid audio file!"};
|
||||
SongException?.Invoke(null, args);
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
var args = new PlaybackExceptionEventArgs {Details = "This audio file might be corrupt!"};
|
||||
SongException?.Invoke(null, args);
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
var args = new PlaybackExceptionEventArgs {Details = "This audio file uses VBR \nor might be corrupt!"};
|
||||
SongException?.Invoke(null, args);
|
||||
}
|
||||
//catch (FileNotFoundException) // TODO: move these to NAudioBackend
|
||||
//{
|
||||
// var args = new PlaybackExceptionEventArgs {Details = "That's not a valid file path!"};
|
||||
// SongException?.Invoke(null, args);
|
||||
//}
|
||||
//catch (ArgumentException)
|
||||
//{
|
||||
// var args = new PlaybackExceptionEventArgs {Details = "That's not a valid file path!"};
|
||||
// SongException?.Invoke(null, args);
|
||||
//}
|
||||
//catch (System.Runtime.InteropServices.COMException)
|
||||
//{
|
||||
// var args = new PlaybackExceptionEventArgs {Details = "This isn't a valid audio file!"};
|
||||
// SongException?.Invoke(null, args);
|
||||
//}
|
||||
//catch (FormatException)
|
||||
//{
|
||||
// var args = new PlaybackExceptionEventArgs {Details = "This audio file might be corrupt!"};
|
||||
// SongException?.Invoke(null, args);
|
||||
//}
|
||||
//catch (InvalidOperationException)
|
||||
//{
|
||||
// var args = new PlaybackExceptionEventArgs {Details = "This audio file uses VBR \nor might be corrupt!"};
|
||||
// SongException?.Invoke(null, args);
|
||||
//}
|
||||
catch (Exception e)
|
||||
{
|
||||
var args = new PlaybackExceptionEventArgs {Details = $"{e.Message}\n{e.StackTrace}"};
|
||||
var args = new PlaybackExceptionEventArgs(e, $"{e.Message}\n{e.StackTrace}");
|
||||
SongException?.Invoke(null, args);
|
||||
}
|
||||
}
|
||||
|
@ -195,12 +209,12 @@ namespace FRESHMusicPlayer
|
|||
/// </summary>
|
||||
public void StopMusic()
|
||||
{
|
||||
if (!Playing) return;
|
||||
if (!FileLoaded) return;
|
||||
|
||||
CurrentBackend.Dispose();
|
||||
CurrentBackend = null;
|
||||
|
||||
Playing = false;
|
||||
FileLoaded = false;
|
||||
Paused = false;
|
||||
SongStopped?.Invoke(null, EventArgs.Empty);
|
||||
}
|
||||
|
@ -210,72 +224,57 @@ namespace FRESHMusicPlayer
|
|||
/// </summary>
|
||||
public void PauseMusic()
|
||||
{
|
||||
if (!Paused) CurrentBackend?.Pause();
|
||||
if (!Paused)
|
||||
CurrentBackend?.Pause();
|
||||
Paused = true;
|
||||
} // Pauses the music without completely disposing it
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resumes playback.
|
||||
/// </summary>
|
||||
public void ResumeMusic()
|
||||
{
|
||||
if (Paused) CurrentBackend?.Play();
|
||||
//playing = true;
|
||||
if (Paused)
|
||||
CurrentBackend?.Play();
|
||||
Paused = false;
|
||||
} // Resumes music that has been paused
|
||||
|
||||
/// <summary>
|
||||
/// Updates the volume of the player during playback to the value of <see cref="CurrentVolume"/>.
|
||||
/// Even if you don't call this, the volume of the player will update whenever the next track plays.
|
||||
/// </summary>
|
||||
public void UpdateSettings()
|
||||
{
|
||||
CurrentBackend.Volume = CurrentVolume;
|
||||
}
|
||||
|
||||
// Other Logic Stuff
|
||||
/// <summary>
|
||||
/// Returns a formatted string of the current playback position.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string SongPositionString() => $"{CurrentBackend.CurrentTime:c} / {CurrentBackend.TotalTime:c}";
|
||||
|
||||
#endregion
|
||||
|
||||
// Integration
|
||||
|
||||
#region DiscordRPC
|
||||
/// <summary>
|
||||
/// Initializes the Discord RPC client. Once it has been initialized, you can set the presence by using <see cref="UpdateRPC(string, string, string)"/>
|
||||
/// </summary>
|
||||
/// <param name="applicationID">The application ID of your app</param>
|
||||
public void InitDiscordRPC(string applicationID)
|
||||
{ // FMP application ID - 656678380283887626
|
||||
Client = new DiscordRpcClient(applicationID);
|
||||
//#region DiscordRPC // TODO: move this to the frontend
|
||||
///// <summary>
|
||||
///// Initializes the Discord RPC client. Once it has been initialized, you can set the presence by using <see cref="UpdateRPC(string, string, string)"/>
|
||||
///// </summary>
|
||||
///// <param name="applicationID">The application ID of your app</param>
|
||||
//public void InitDiscordRPC(string applicationID)
|
||||
//{ // FMP application ID - 656678380283887626
|
||||
// Client = new DiscordRpcClient(applicationID);
|
||||
|
||||
Client.OnReady += (sender, e) => { Console.WriteLine("Received Ready from user {0}", e.User.Username); };
|
||||
Client.OnPresenceUpdate += (sender, e) => { Console.WriteLine("Received Update! {0}", e.Presence); };
|
||||
Client.Initialize();
|
||||
}
|
||||
// Client.OnReady += (sender, e) => { Console.WriteLine("Received Ready from user {0}", e.User.Username); };
|
||||
// Client.OnPresenceUpdate += (sender, e) => { Console.WriteLine("Received Update! {0}", e.Presence); };
|
||||
// Client.Initialize();
|
||||
//}
|
||||
|
||||
public void UpdateRPC(string Activity, string Artist = null, string Title = null)
|
||||
{
|
||||
Client?.SetPresence(new RichPresence()
|
||||
{
|
||||
Details = PlayerUtils.TruncateBytes(Title, 120),
|
||||
State = PlayerUtils.TruncateBytes(Artist, 120),
|
||||
Assets = new Assets()
|
||||
{
|
||||
LargeImageKey = "icon",
|
||||
SmallImageKey = Activity
|
||||
},
|
||||
Timestamps = Timestamps.Now
|
||||
}
|
||||
);
|
||||
}
|
||||
//public void UpdateRPC(string Activity, string Artist = null, string Title = null)
|
||||
//{
|
||||
// Client?.SetPresence(new RichPresence()
|
||||
// {
|
||||
// Details = PlayerUtils.TruncateBytes(Title, 120),
|
||||
// State = PlayerUtils.TruncateBytes(Artist, 120),
|
||||
// Assets = new Assets()
|
||||
// {
|
||||
// LargeImageKey = "icon",
|
||||
// SmallImageKey = Activity
|
||||
// },
|
||||
// Timestamps = Timestamps.Now
|
||||
// }
|
||||
// );
|
||||
//}
|
||||
|
||||
public void DisposeRPC() => Client?.Dispose();
|
||||
//public void DisposeRPC() => Client?.Dispose();
|
||||
|
||||
#endregion
|
||||
//#endregion
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Squid Grill")]
|
||||
[assembly: AssemblyProduct("FRESHMusicPlayer.Player")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2020")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2021")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
|
@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
|||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("2.9.0.0")]
|
||||
[assembly: AssemblyFileVersion("2.9.0.0")]
|
||||
[assembly: AssemblyVersion("3.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("3.0.0.0")]
|
||||
|
|
|
@ -10,30 +10,6 @@ namespace FRESHMusicPlayer.Utilities
|
|||
{
|
||||
private static readonly Random rng = new Random();
|
||||
|
||||
public static List<string> ShuffleQueue(this Player player, List<string> list)
|
||||
{
|
||||
var listtosort = new List<string>();
|
||||
var listtoreinsert = new List<string>();
|
||||
var number = 0;
|
||||
foreach (var x in list)
|
||||
{
|
||||
if (player.QueuePosition < number) listtosort.Add(x);
|
||||
else listtoreinsert.Add(x);
|
||||
number++;
|
||||
}
|
||||
|
||||
var n = listtosort.Count;
|
||||
while (n > 1)
|
||||
{
|
||||
n--;
|
||||
var k = rng.Next(n + 1);
|
||||
var value = listtosort[k];
|
||||
listtosort[k] = listtosort[n];
|
||||
listtosort[n] = value;
|
||||
}
|
||||
foreach (var x in listtosort) listtoreinsert.Add(x);
|
||||
return listtoreinsert;
|
||||
}
|
||||
public static string TruncateBytes(string str, int bytes)
|
||||
{
|
||||
if (Encoding.UTF8.GetByteCount(str) <= bytes) return str;
|
||||
|
|
|
@ -8,19 +8,4 @@ namespace FRESHMusicPlayer.Utilities
|
|||
public int Version { get; set; }
|
||||
public List<string> Songs { get; set; }
|
||||
}
|
||||
public class DatabaseTrack
|
||||
{
|
||||
public string Path { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Artist { get; set; }
|
||||
public string Album { get; set; }
|
||||
public int TrackNumber { get; set; }
|
||||
public int Length { get; set; }
|
||||
}
|
||||
public class DatabasePlaylist
|
||||
{
|
||||
public int DatabasePlaylistID { get; set; }
|
||||
public string Name { get; set; }
|
||||
public List<string> Tracks { get; set; }
|
||||
}
|
||||
}
|
81
FRESHMusicPlayer.Player/FmpCdLibBackend/FmpCdLibBackend.cs
Normal file
81
FRESHMusicPlayer.Player/FmpCdLibBackend/FmpCdLibBackend.cs
Normal file
|
@ -0,0 +1,81 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Composition;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using CDLib;
|
||||
using FRESHMusicPlayer.Backends;
|
||||
|
||||
namespace FmpCdLibBackend
|
||||
{
|
||||
[Export(typeof(IAudioBackend))]
|
||||
public class FmpCdLibBackend : IAudioBackend
|
||||
{
|
||||
private IAudioCDPlayer player;
|
||||
public TimeSpan CurrentTime { get => player.CurrentPosition; set => player.Seek(value); }
|
||||
|
||||
public TimeSpan TotalTime { get; private set; }
|
||||
|
||||
public float Volume { get => (float)player.Volume; set => player.Volume = value; }
|
||||
|
||||
public event EventHandler<EventArgs> OnPlaybackStopped;
|
||||
|
||||
public FmpCdLibBackend()
|
||||
{
|
||||
player = AudioCDPlayer.GetPlayer();
|
||||
player.FinishedPlayingTrack += Player_FinishedPlayingTrack;
|
||||
}
|
||||
//static FmpCdLibBackend()
|
||||
//{
|
||||
// Assembly.Load(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "FRESHMusicPlayer", "Backends", "CDLib.winmd"));
|
||||
// SetDllDirectory(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "FRESHMusicPlayer", "Backends"));
|
||||
//}
|
||||
|
||||
private void Player_FinishedPlayingTrack()
|
||||
{
|
||||
OnPlaybackStopped.Invoke(null, EventArgs.Empty);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
player.Pause();
|
||||
//player.Dispose();
|
||||
}
|
||||
|
||||
public void LoadSong(string file)
|
||||
{
|
||||
if (Path.GetExtension(file).ToUpper() != ".CDA") throw new Exception("Not a CD");
|
||||
// super hacky; assumes that the path is something like D:\Track01.cda, might be a better way to do this
|
||||
var driveLetter = char.Parse(file.Substring(0, 1));
|
||||
var trackNumber = int.Parse(file.Substring(8, 2));
|
||||
|
||||
var drives = player.GetDrives();
|
||||
foreach (var drive in drives)
|
||||
{
|
||||
if (drive.DriveLetter == driveLetter)
|
||||
{
|
||||
var trackToPlay = drive.InsertedMedia.Tracks[trackNumber - 1];
|
||||
TotalTime = trackToPlay.Duration;
|
||||
player.PlayTrack(trackToPlay);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Pause()
|
||||
{
|
||||
player.Pause();
|
||||
}
|
||||
|
||||
public void Play()
|
||||
{
|
||||
player.Resume();
|
||||
}
|
||||
[DllImport("kernel32")]
|
||||
private static extern void SetDllDirectory(string pathName);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{31D77A1D-F161-42E8-826E-3E27E6566B28}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>FmpCdLibBackend</RootNamespace>
|
||||
<AssemblyName>FmpCdLibBackend</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="CDLib, Version=255.255.255.255, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\CDLib\Release\CDLib.winmd</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="FmpCdLibBackend.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\FRESHMusicPlayer.Player\FRESHMusicPlayer.Core.csproj">
|
||||
<Project>{ffe8eafd-7faa-4503-9364-2643821a2bc8}</Project>
|
||||
<Name>FRESHMusicPlayer.Core</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Composition">
|
||||
<Version>1.4.1</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("FmpCdLibBackend")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("FmpCdLibBackend")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2021")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("31d77a1d-f161-42e8-826e-3e27e6566b28")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using FRESHMusicPlayer;
|
||||
using FRESHMusicPlayer.Handlers;
|
||||
|
@ -17,9 +18,20 @@ namespace WinformsTest
|
|||
player.SongChanged += Player_songChanged;
|
||||
player.SongStopped += Player_songStopped;
|
||||
player.SongException += Player_songException;
|
||||
player.Queue.QueueChanged += Queue_QueueChanged;
|
||||
library = DatabaseHandler.ReadSongs();
|
||||
}
|
||||
|
||||
private void Queue_QueueChanged(object sender, EventArgs e)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
foreach (var track in player.Queue.Queue)
|
||||
{
|
||||
builder.AppendLine(track);
|
||||
}
|
||||
MessageBox.Show(builder.ToString());
|
||||
}
|
||||
|
||||
private void Player_songException(object sender, PlaybackExceptionEventArgs e)
|
||||
{
|
||||
MessageBox.Show("something did a fucky wucky");
|
||||
|
@ -37,22 +49,33 @@ namespace WinformsTest
|
|||
|
||||
private void button1_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (player.Paused) player.ResumeMusic();
|
||||
else player.PauseMusic();
|
||||
var builder = new StringBuilder();
|
||||
foreach (var track in player.Queue.Queue)
|
||||
{
|
||||
builder.AppendLine(track);
|
||||
}
|
||||
MessageBox.Show(builder.ToString());
|
||||
player.Queue.ManualShuffle();
|
||||
}
|
||||
|
||||
private void button2_Click(object sender, EventArgs e)
|
||||
{
|
||||
player.Queue.Shuffle = !player.Queue.Shuffle;
|
||||
MessageBox.Show(player.Queue.Shuffle.ToString());
|
||||
}
|
||||
|
||||
private void button3_Click(object sender, EventArgs e)
|
||||
{
|
||||
var openFileDialog1 = new OpenFileDialog();
|
||||
if (openFileDialog1.ShowDialog() != DialogResult.OK) return;
|
||||
player.AddQueue(openFileDialog1.FileName);
|
||||
player.PlayMusic();
|
||||
player.CurrentVolume = 0.2f;
|
||||
player.UpdateSettings();
|
||||
var list = new List<string>();
|
||||
for (var i = 1; i < 100; i++)
|
||||
list.Add(i.ToString());
|
||||
player.Queue.Add(list.ToArray());
|
||||
//var openFileDialog1 = new OpenFileDialog();
|
||||
//if (openFileDialog1.ShowDialog() != DialogResult.OK) return;
|
||||
//player.Queue.Add(openFileDialog1.FileName);
|
||||
//player.PlayMusic();
|
||||
//player.CurrentVolume = 0.2f;
|
||||
//player.UpdateSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
|
||||
<PackageReference Include="VideoLAN.LibVLC.Windows" Version="3.0.11" />
|
||||
</ItemGroup>
|
||||
</Project>
|
18
README.md
18
README.md
|
@ -1,21 +1,25 @@
|
|||
banner goes here eventually
|
||||
# FRESHMusicPlayer-Core
|
||||
Music Player component for .NET apps - designed to be used for the FRESHMusicPlayer project but can be used on anything :)
|
||||
audio library abstraction library - designed to be used for the FRESHMusicPlayer project but can be used on anything :)
|
||||
- [**Support/Discussion Discord Server**](https://discord.gg/mFGFT8K)
|
||||
- [**Documentation (WIP)**]()
|
||||
## Features
|
||||
- Abstracts music playback into a simple API
|
||||
- Provides a library that's shared between all FMP Core based apps
|
||||
- Has built in support for integrations with services like Discord
|
||||
- todo: add more stuff here
|
||||
## Usage
|
||||
```
|
||||
using FRESHMusicPlayer;
|
||||
|
||||
Player player = new Player();
|
||||
var player = new Player();
|
||||
string path = "Can be a file path, or a URL to a network stream";
|
||||
player.AddQueue(path); // Everything in FMP runs on a queue
|
||||
player.PlayMusic(); // Play through the queue
|
||||
player.PlayMusic(path); // Clear the queue, add the track to the queue, and play
|
||||
// or
|
||||
player.Queue.Add(path);
|
||||
player.PlayMusic(); // Plays through the queue
|
||||
```
|
||||
[**Documentation (WIP)**]()
|
||||
### Platforms
|
||||
**Windows** - NAudio is required for audio playback
|
||||
**Other platforms** - You'll need to include the [VLC audio plugin](https://github.com/DeclanHoare/FmpVlcBackend) in the output directory of your app for audio playback to work. The user will also need to have a global installation of VLC available. Hoping to replace this with something lighterweight in the future.
|
||||
## Projects that use FMP Core
|
||||
- [**FRESHMusicPlayer**](https://github.com/royce551/freshmusicplayer)
|
||||
- [**FRESHMusicPlayer-WinForms**](https://github.com/royce551/freshmusicplayer-wpfui)
|
||||
|
|
Loading…
Reference in a new issue