diff --git a/E.Deezer/Api/Album.cs b/E.Deezer/Api/Album.cs index 0d7a4ef..931dd42 100644 --- a/E.Deezer/Api/Album.cs +++ b/E.Deezer/Api/Album.cs @@ -52,10 +52,10 @@ public string ArtistName public DeezerClient Client { get; set; } public void Deserialize(DeezerClient aClient) { Client = aClient; } - [Obsolete("Please use GetPicture instead.")] + [Obsolete("Please use GetPicture instead.", true)] public string GetCover(PictureSize aSize) { return GetPicture(aSize); } - [Obsolete("Please use HasPicture instead.")] + [Obsolete("Please use HasPicture instead.", true)] public bool HasCover(PictureSize aSize) { return HasPicture(aSize); } diff --git a/E.Deezer/Api/Internal/DeezerCreateResponse.cs b/E.Deezer/Api/Internal/DeezerCreateResponse.cs new file mode 100644 index 0000000..a36f83f --- /dev/null +++ b/E.Deezer/Api/Internal/DeezerCreateResponse.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using RestSharp.Deserializers; + +namespace E.Deezer.Api +{ + //Retrun value of all Deezer API calls + internal class DeezerCreateResponse + { + [DeserializeAs(Name = "id")] + public uint Id { get; set; } + } +} diff --git a/E.Deezer/Api/Internal/Permissions.cs b/E.Deezer/Api/Internal/Permissions.cs index 7893fa9..c8db903 100644 --- a/E.Deezer/Api/Internal/Permissions.cs +++ b/E.Deezer/Api/Internal/Permissions.cs @@ -42,19 +42,47 @@ internal class OAuthPermissions : IPermissions [DeserializeAs(Name="listening_history")] public bool HasListeningHistory {get; set; } + //TODO - Check a method that has multiple permissions... public bool HasPermission(DeezerPermissions aPermission) { - switch (aPermission) + bool permission = true; + + if (aPermission.HasFlag(DeezerPermissions.BasicAccess)) + { + permission &= HasBasicAccess; + } + + if (aPermission.HasFlag(DeezerPermissions.DeleteLibrary)) + { + permission &= HasDeleteLibrary; + } + + if (aPermission.HasFlag(DeezerPermissions.Email)) + { + permission &= HasEmail; + } + + if (aPermission.HasFlag(DeezerPermissions.ListeningHistory)) { - case DeezerPermissions.BasicAccess: { return HasBasicAccess; } - case DeezerPermissions.DeleteLibrary: { return HasDeleteLibrary; } - case DeezerPermissions.Email: { return HasEmail; } - case DeezerPermissions.ListeningHistory: { return HasListeningHistory; } - case DeezerPermissions.ManageCommunity: { return HasManageCommunity; } - case DeezerPermissions.ManageLibrary: { return HasManageLibrary; } - case DeezerPermissions.OfflineAccess: { return HasOfflineAccess; } - default: { return false; } + permission &= HasListeningHistory; } + + if (aPermission.HasFlag(DeezerPermissions.ManageCommunity)) + { + permission &= HasManageCommunity; + } + + if (aPermission.HasFlag(DeezerPermissions.ManageLibrary)) + { + permission &= HasManageLibrary; + } + + if (aPermission.HasFlag(DeezerPermissions.OfflineAccess)) + { + permission &= HasOfflineAccess; + } + + return permission; } } } diff --git a/E.Deezer/Api/Playlist.cs b/E.Deezer/Api/Playlist.cs index cd94f7d..8a61ee9 100644 --- a/E.Deezer/Api/Playlist.cs +++ b/E.Deezer/Api/Playlist.cs @@ -25,7 +25,22 @@ public interface IPlaylist : IObjectWithImage Task> GetTracks(uint aStart, uint aCount); Task Rate(int aRating); - } + + //Manage Tracks + Task AddTrack(ITrack aTrack); + Task AddTrack(Int64 aTrackId); + + Task AddTracks(IEnumerable aTracks); + Task AddTracks(IEnumerable aTrackIds); + Task AddTracks(string aTrackIds); + + Task RemoveTrack(ITrack aTrack); + Task RemoveTrack(Int64 aTrackId); + + Task RemoveTracks(IEnumerable aTracks); + Task RemoveTracks(IEnumerable aTrackIds); + Task RemoveTracks(string aTrackIds); + } internal class Playlist : ObjectWithImage, IPlaylist, IDeserializable { @@ -76,7 +91,6 @@ public Task> GetTracks(uint aStart, uint aCount) }, Client.CancellationToken, TaskContinuationOptions.NotOnCanceled, TaskScheduler.Default); } - public Task Rate(int aRating) { if (aRating < 1 || aRating > 5) { throw new ArgumentOutOfRangeException("aRating", "Rating value should be between 1 and 5 (inclusive)"); } @@ -91,7 +105,88 @@ public Task Rate(int aRating) } - public override string ToString() + public Task AddTrack(ITrack aTrack) { return AddTrack(aTrack.Id); } + public Task AddTrack(Int64 aTrackId) { return AddTracks(aTrackId.ToString()); } + + public Task AddTracks(IEnumerable aTrackIds) + { + if (aTrackIds.Count() > 0) + { + return AddTracks(string.Join(",", aTrackIds.Select((v) => v.ToString()))); + } + else + { + throw new ArgumentException("Must provide at least one track ID", "aTrackIds"); + } + + } + + public Task AddTracks(IEnumerable aTracks) + { + if (aTracks.Count() > 0) + { + return AddTracks(string.Join(",", aTracks.Select((v) => v.Id.ToString()))); + } + else + { + throw new ArgumentException("Must provide at least one track ID", "aTrackIds"); + } + } + + public Task AddTracks(string aTrackIds) + { + List parms = new List() + { + RequestParameter.GetNewUrlSegmentParamter("playlist_id", Id), + RequestParameter.GetNewQueryStringParameter("songs", aTrackIds) + }; + + return Client.Post("playlist/{playlist_id}/tracks", parms, DeezerPermissions.ManageLibrary); + } + + + public Task RemoveTrack(ITrack aTrack) { return RemoveTrack(aTrack.Id); } + public Task RemoveTrack(Int64 aTrackId) { return RemoveTracks(aTrackId.ToString()); } + + public Task RemoveTracks(IEnumerable aTrackIds) + { + if (aTrackIds.Count() > 0) + { + return RemoveTracks(string.Join(",", aTrackIds.Select((v) => v.ToString()))); + } + else + { + throw new ArgumentException("Must provide at least one track ID", "aTrackIds"); + } + + } + + public Task RemoveTracks(IEnumerable aTracks) + { + if (aTracks.Count() > 0) + { + return RemoveTracks(string.Join(",", aTracks.Select((v) => v.Id.ToString()))); + } + else + { + throw new ArgumentException("Must provide at least one track ID", "aTrackIds"); + } + } + + public Task RemoveTracks(string aTrackIds) + { + List parms = new List() + { + RequestParameter.GetNewUrlSegmentParamter("playlist_id", Id), + RequestParameter.GetNewQueryStringParameter("songs", aTrackIds) + }; + + return Client.Delete("playlist/{playlist_id}/tracks", parms, DeezerPermissions.ManageLibrary | DeezerPermissions.DeleteLibrary); + } + + + + public override string ToString() { return string.Format("E.Deezer: Playlist({0} [{1}])", Title, CreatorName); } diff --git a/E.Deezer/Api/Track.cs b/E.Deezer/Api/Track.cs index f924127..b5f5b47 100644 --- a/E.Deezer/Api/Track.cs +++ b/E.Deezer/Api/Track.cs @@ -11,17 +11,20 @@ namespace E.Deezer.Api { public interface ITrack : IObjectWithImage { - uint Id { get; set; } + Int64 Id { get; set; } string Title { get; set; } string Link { get; set; } uint Duration { get; set; } DateTime ReleaseDate { get; set; } + DateTime TimeAdd { get; set; } bool Explicit { get; set; } string Preview { get; set; } string ArtistName { get; } string AlbumName { get; } IArtist Artist { get; } IAlbum Album { get; } + uint Number { get; } + uint Disc { get; } string GetCover(PictureSize aSize); bool HasCover(PictureSize aSize); @@ -30,9 +33,11 @@ public interface ITrack : IObjectWithImage internal class Track : ObjectWithImage, ITrack, IDeserializable { - public uint Id { get; set; } + public Int64 Id { get; set; } public string Title { get; set; } public string Link { get; set; } + [DeserializeAs(Name = "time_add")] + public DateTime TimeAdd { get; set; } public uint Duration { get; set; } public DateTime ReleaseDate { get; set; } public string Artwork { get; set; } @@ -41,6 +46,12 @@ internal class Track : ObjectWithImage, ITrack, IDeserializable public IArtist Artist { get { return ArtistInternal; } } public IAlbum Album { get { return AlbumInternal; } } + [DeserializeAs(Name = "track_position")] + public uint Number { get; set; } + + [DeserializeAs(Name = "disc_number")] + public uint Disc { get; set; } + public string ArtistName { get @@ -72,10 +83,10 @@ public void Deserialize(DeezerClient aClient) Client = aClient; } - [Obsolete("Please use GetPicture instead.")] + [Obsolete("Please use GetPicture instead.", true)] public string GetCover(PictureSize aSize) { return GetPicture(aSize); } - [Obsolete("Please use HasPicture instead.")] + [Obsolete("Please use HasPicture instead.", true)] public bool HasCover(PictureSize aSize) { return HasPicture(aSize); } public override string ToString() diff --git a/E.Deezer/Api/User.cs b/E.Deezer/Api/User.cs index 29db90e..9f4ddcb 100644 --- a/E.Deezer/Api/User.cs +++ b/E.Deezer/Api/User.cs @@ -63,7 +63,11 @@ public interface IUser : IObjectWithImage Task> GetRecommendedPlaylists(); Task> GetRecommendedPlaylists(uint aCount); Task> GetRecommendedPlaylists(uint aStart, uint aCount); - } + + Task CreatePlaylist(string title); + + Task AddToPlaylist(uint playlistId, string songids); + } internal class User : ObjectWithImage, IUser, IDeserializable { @@ -145,5 +149,27 @@ private Task> Get(string aMethod, DeezerPermi public Task> GetRecommendedTracks(uint aCount) { return GetRecommendedTracks(0, aCount); } public Task> GetRecommendedTracks(uint aStart, uint aCount) { return Get("recommendations/tracks", DeezerPermissions.BasicAccess, aStart, aCount); } + public Task CreatePlaylist(string title) + { + List parms = new List() + { + RequestParameter.GetNewUrlSegmentParamter("id", Id), + RequestParameter.GetNewQueryStringParameter("title", title) + }; + + return Client.Post("user/{id}/playlists", parms, DeezerPermissions.ManageLibrary).ContinueWith(t => t.Result.Id); + } + + [Obsolete("Preferable to use IPlaylist.AddTrack(s) methods instead")] + public Task AddToPlaylist(uint playlistId, string songids) + { + List parms = new List() + { + RequestParameter.GetNewUrlSegmentParamter("playlist_id", playlistId), + RequestParameter.GetNewQueryStringParameter("songs", songids) + }; + + return Client.Post("playlist/{playlist_id}/tracks", parms, DeezerPermissions.ManageLibrary); + } } } diff --git a/E.Deezer/Deezer.cs b/E.Deezer/Deezer.cs index 20264eb..f3b7bd0 100644 --- a/E.Deezer/Deezer.cs +++ b/E.Deezer/Deezer.cs @@ -15,15 +15,19 @@ namespace E.Deezer /// public class Deezer : IDisposable { + private string iVersion; + private DeezerSession iSession; - private IBrowseEndpoint iBrowse; - private ISearchEndpoint iSearch; - private IUserEndpoint iUser; - private IRadioEndpoint iRadio; - private DeezerClient iClient; + private readonly IBrowseEndpoint iBrowse; + private readonly ISearchEndpoint iSearch; + private readonly IUserEndpoint iUser; + private readonly IRadioEndpoint iRadio; + private readonly DeezerClient iClient; internal Deezer(DeezerSession aSession, bool underTest = false) { + //iVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(); + iSession = aSession; if (underTest) { iClient = new DeezerClient(iSession, true); } else { iClient = new DeezerClient(iSession); } @@ -43,7 +47,7 @@ internal Deezer(DeezerSession aSession, bool underTest = false) public Task GetServiceInformation() { - return iClient.Get("infos").ContinueWith((aTask) => { return aTask.Result; }, iClient.CancellationToken, TaskContinuationOptions.NotOnCanceled, TaskScheduler.Default); + return iClient.GetPlain("infos").ContinueWith((aTask) => { return aTask.Result; }, iClient.CancellationToken, TaskContinuationOptions.NotOnCanceled, TaskScheduler.Default); } //'OAuth' diff --git a/E.Deezer/DeezerClient.cs b/E.Deezer/DeezerClient.cs index 4824334..e0c9735 100644 --- a/E.Deezer/DeezerClient.cs +++ b/E.Deezer/DeezerClient.cs @@ -52,7 +52,13 @@ internal Task> Get(string aMethod, IList } internal Task Get(string aMethod) { - return DoGet>(aMethod, RequestParameter.EmptyList).ContinueWith((aTask) => aTask.Result.Data, iExecutor.CancellationToken, TaskContinuationOptions.NotOnCanceled, TaskScheduler.Default); + return DoGet>(aMethod, RequestParameter.EmptyList).ContinueWith((aTask) => aTask.Result.Data, CancellationToken, TaskContinuationOptions.NotOnCanceled, TaskScheduler.Default); + } + + internal Task GetPlain(string aMethod) + { + return iExecutor.ExecuteGet(aMethod, RequestParameter.EmptyList) + .ContinueWith((aTask) => aTask.Result.Data, CancellationToken, TaskContinuationOptions.NotOnCanceled, TaskScheduler.Default); } private Task DoGet(string aMethod, IEnumerable aParams) where T : IHasError @@ -75,6 +81,36 @@ internal Task Post(string aMethod, IList aParams, Deeze return iExecutor.ExecutePost(aMethod, aParams).ContinueWith((aTask) => aTask.Result.Data, CancellationToken, TaskContinuationOptions.NotOnCanceled, TaskScheduler.Default); } + internal Task Post(string aMethod, IList aParams, DeezerPermissions aRequiredPermission) + { + if (!IsAuthenticated) { throw new NotLoggedInException(); } + if (!HasPermission(aRequiredPermission)) { throw new DeezerPermissionsException(aRequiredPermission); } + + AddDefaultsToParamList(aParams); + + return iExecutor.ExecutePost(aMethod, aParams).ContinueWith((aTask) => aTask.Result.Data, CancellationToken, TaskContinuationOptions.NotOnCanceled, TaskScheduler.Default); + } + + //Performs a DELETE request + internal Task Delete(string aMethod, IList aParams, DeezerPermissions aRequiredPermission) + { + if (!IsAuthenticated) { throw new NotLoggedInException(); } + if (!HasPermission(aRequiredPermission)) { throw new DeezerPermissionsException(aRequiredPermission); } + + AddDefaultsToParamList(aParams); + + return iExecutor.ExecuteDelete(aMethod, aParams).ContinueWith((aTask) => aTask.Result.Data, CancellationToken, TaskContinuationOptions.NotOnCanceled, TaskScheduler.Default); + } + + internal Task Delete(string aMethod, IList aParams, DeezerPermissions aRequiredPermission) + { + if (!IsAuthenticated) { throw new NotLoggedInException(); } + if (!HasPermission(aRequiredPermission)) { throw new DeezerPermissionsException(aRequiredPermission); } + + AddDefaultsToParamList(aParams); + + return iExecutor.ExecuteDelete(aMethod, aParams).ContinueWith((aTask) => aTask.Result.Data, CancellationToken, TaskContinuationOptions.NotOnCanceled, TaskScheduler.Default); + } //'OAuth' Stuff @@ -174,10 +210,10 @@ internal IEnumerable Transform(DeezerFragment aF } - private void AddDefaultsToParamList(IList aParams) { AddToParamList(aParams, uint.MaxValue, uint.MaxValue); } + private void AddDefaultsToParamList(IList aParams) { AddToParamList(aParams, uint.MinValue, uint.MaxValue); } private void AddToParamList(IList aParams, uint aStart, uint aCount) { - if (aCount < uint.MaxValue && aStart < uint.MaxValue) + if (aCount <= uint.MaxValue && aStart <= uint.MaxValue) { aParams.Add(RequestParameter.GetNewQueryStringParameter("index", aStart)); aParams.Add(RequestParameter.GetNewQueryStringParameter("limit", aCount)); diff --git a/E.Deezer/DeezerPermissions.cs b/E.Deezer/DeezerPermissions.cs index c4b7c7c..92ec46c 100644 --- a/E.Deezer/DeezerPermissions.cs +++ b/E.Deezer/DeezerPermissions.cs @@ -7,20 +7,55 @@ namespace E.Deezer { public static class Permissions { + private const string dBasicAccess = "basic_access"; + private const string dEmail = "email"; + private const string dOffliceAccess = "offline_access"; + private const string dManageLibrary = "manage_library"; + private const string dManageCommunity = "manage_community"; + private const string dDeleteLibrary = "delete_library"; + private const string dListeningHistory = "listening_history"; + + public static string PermissionToString(this DeezerPermissions aPermission) { - switch (aPermission) + List perms = new List(10); + + if (aPermission.HasFlag(DeezerPermissions.BasicAccess)) { + perms.Add(dBasicAccess); + } - case DeezerPermissions.BasicAccess: { return "basic_access"; } - case DeezerPermissions.Email: { return "email"; } - case DeezerPermissions.OfflineAccess: { return "offline_access"; } - case DeezerPermissions.ManageLibrary: { return "manage_library"; } - case DeezerPermissions.ManageCommunity: { return "manage_community"; } - case DeezerPermissions.DeleteLibrary: { return "delete_history"; } - case DeezerPermissions.ListeningHistory: { return "listening_history"; } - default: { return string.Empty; } + if (aPermission.HasFlag(DeezerPermissions.DeleteLibrary)) + { + perms.Add(dDeleteLibrary); + } + + if (aPermission.HasFlag(DeezerPermissions.Email)) + { + perms.Add(dEmail); + } + + if (aPermission.HasFlag(DeezerPermissions.ListeningHistory)) + { + perms.Add(dListeningHistory); } + + if (aPermission.HasFlag(DeezerPermissions.ManageCommunity)) + { + perms.Add(dManageCommunity); + } + + if (aPermission.HasFlag(DeezerPermissions.ManageLibrary)) + { + perms.Add(dManageLibrary); + } + + if (aPermission.HasFlag(DeezerPermissions.OfflineAccess)) + { + perms.Add(dOffliceAccess); + } + + return string.Join(", ", perms); } } diff --git a/E.Deezer/E.Deezer.csproj b/E.Deezer/E.Deezer.csproj index c8d7546..72a7266 100644 --- a/E.Deezer/E.Deezer.csproj +++ b/E.Deezer/E.Deezer.csproj @@ -20,7 +20,7 @@ None.None.None.Increment None.None.None.Increment IncrementOnDemand.Increment.DateStamp.TimeStamp - 2.2.0.271 + 2.2.0.279 ..\ @@ -66,6 +66,7 @@ + diff --git a/E.Deezer/Endpoint/ChartsEndpoint.cs b/E.Deezer/Endpoint/ChartsEndpoint.cs index f63c62d..8df91e9 100644 --- a/E.Deezer/Endpoint/ChartsEndpoint.cs +++ b/E.Deezer/Endpoint/ChartsEndpoint.cs @@ -36,19 +36,19 @@ internal class ChartsEndpoint : IChartsEndpoint public Task> GetAlbumChart() { return GetAlbumChart(0, iClient.ResultSize); } public Task> GetAlbumChart(uint aCount) { return GetAlbumChart(0, aCount); } - public Task> GetAlbumChart(uint aStart, uint aCount) { return Get("charts/{id}/albums", 0, aStart, aCount); } + public Task> GetAlbumChart(uint aStart, uint aCount) { return Get("chart/{id}/albums", 0, aStart, aCount); } public Task> GetArtistChart() { return GetArtistChart(0, iClient.ResultSize); } public Task> GetArtistChart(uint aCount) { return GetArtistChart(0, aCount); } - public Task> GetArtistChart(uint aStart, uint aCount) { return Get("charts/{id}/artists", 0, aStart, aCount); } + public Task> GetArtistChart(uint aStart, uint aCount) { return Get("chart/{id}/artists", 0, aStart, aCount); } public Task> GetPlaylistChart() { return GetPlaylistChart(0, iClient.ResultSize); } public Task> GetPlaylistChart(uint aCount) { return GetPlaylistChart(0, aCount); } - public Task> GetPlaylistChart(uint aStart, uint aCount) { return Get("charts/{id}/playlists", 0, aStart, aCount); } + public Task> GetPlaylistChart(uint aStart, uint aCount) { return Get("chart/{id}/playlists", 0, aStart, aCount); } public Task> GetTrackChart() { return GetTrackChart(0, iClient.ResultSize); } public Task> GetTrackChart(uint aCount) { return GetTrackChart(0, aCount); } - public Task> GetTrackChart(uint aStart, uint aCount) { return Get("charts/{id}/track", 0, aStart, aCount); } + public Task> GetTrackChart(uint aStart, uint aCount) { return Get("chart/{id}/track", 0, aStart, aCount); } //Internal wrapper around get for all ChartEndpoint methods :) diff --git a/E.Deezer/ExecutorService.cs b/E.Deezer/ExecutorService.cs index 0266ac7..7fea7dd 100644 --- a/E.Deezer/ExecutorService.cs +++ b/E.Deezer/ExecutorService.cs @@ -46,6 +46,11 @@ public Task> ExecutePost(string aMethod, IEnumerable(aMethod, Method.POST, aParams); } + public Task> ExecuteDelete(string aMethod, IEnumerable aParams) + { + return Execute(aMethod, Method.DELETE, aParams); + } + private Task> Execute(string aMethodUrl, Method aMethodType, IEnumerable aParams) diff --git a/E.Deezer/Properties/AssemblyInfo.cs b/E.Deezer/Properties/AssemblyInfo.cs index fea0af2..94e04b9 100644 --- a/E.Deezer/Properties/AssemblyInfo.cs +++ b/E.Deezer/Properties/AssemblyInfo.cs @@ -33,8 +33,8 @@ // 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.2.0.271")] -[assembly: AssemblyFileVersion("2.2.0.271")] +[assembly: AssemblyVersion("2.2.0.279")] +[assembly: AssemblyFileVersion("2.2.0.279")] [assembly: NeutralResourcesLanguageAttribute("en-GB")] // Make sure we can access some of the internals to the testing library. diff --git a/README.md b/README.md index cafe259..ccc1a4c 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ See more in the [Wiki](http://github.com/projectgoav/E.Deezer/wiki) ##License (MIT) -Copyright (c) 2016 +Copyright (c) 2017 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal