diff --git a/configurations/homie/modules/home-assistant/netdaemon/apps/Spotify/PauseUnpause/PauseUnpause.cs b/configurations/homie/modules/home-assistant/netdaemon/apps/Spotify/PauseUnpause/PauseUnpause.cs index 76b4de47..15d2de29 100644 --- a/configurations/homie/modules/home-assistant/netdaemon/apps/Spotify/PauseUnpause/PauseUnpause.cs +++ b/configurations/homie/modules/home-assistant/netdaemon/apps/Spotify/PauseUnpause/PauseUnpause.cs @@ -1,5 +1,3 @@ -using System; - using HomeAssistantGenerated; using NetDaemon.AppModel; @@ -16,34 +14,27 @@ namespace NetDaemonConfig.Apps.Spotify.PauseUnpause [NetDaemonApp] public class PauseUnpause { + private static void CallBack(PauseUnpauseData e, Services services) + { + if (e.pause) + { + services.Spotifyplus.PlayerMediaPause( + entityId: Globals.DefaultEntityId, + deviceId: Globals.DefaultDevId); + } + else + { + services.Spotifyplus.PlayerMediaResume( + entityId: Globals.DefaultEntityId, + deviceId: Globals.DefaultDevId); + } + } + public PauseUnpause(IHaContext ha, Services services) { ha.RegisterServiceCallBack( "spotify_pause_unpause", - (e) => - { - try - { - if (e.pause) - { - services.Spotifyplus.PlayerMediaPause( - entityId: Globals.DefaultEntityId, - deviceId: Globals.DefaultDevId); - } - else - { - services.Spotifyplus.PlayerMediaResume( - entityId: Globals.DefaultEntityId, - deviceId: Globals.DefaultDevId); - } - } - catch (Exception error) - { - services.Notify.PersistentNotification( - message: error.Message + "\n" + e.ToString(), - title: "Erreur Spotify"); - } - } + (e) => Globals.RunSpotifyCallback(services, e, CallBack) ); } } diff --git a/configurations/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayAlbum/PlayAlbum.cs b/configurations/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayAlbum/PlayAlbum.cs index 46467b55..5556a2c6 100644 --- a/configurations/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayAlbum/PlayAlbum.cs +++ b/configurations/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayAlbum/PlayAlbum.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.Reflection; using System.Text.Json; +using System.Threading.Tasks; using FuzzySharp; using FuzzySharp.Extractor; @@ -31,89 +32,82 @@ namespace NetDaemonConfig.Apps.Spotify.PlayAlbum PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower }; + private async Task CallBack(PlayAlbumData e, Services services) + { + string uri; + + if (e.artist is not null && e.artist != "") + { + SpotifyplusSearchArtistsResponse? artistResult = ( + await services.Spotifyplus.SearchArtistsAsync( + criteria: e?.artist ?? + throw new TargetException($"The artist {e?.artist} could not be found."), + limitTotal: 1, + entityId: Globals.DefaultEntityId, + // My Defaults + market: "CA", + includeExternal: "audio" + ) + ).Value.Deserialize(_jsonOptions); + + string artistId = artistResult?.Result?.Items?[0]?.Id ?? + throw new TargetException($"The artist {e?.artist} could not be found."); + + SpotifyPlusGetArtistAlbumsResponse? result = ( + await services.Spotifyplus.GetArtistAlbumsAsync( + artistId: artistId, + entityId: Globals.DefaultEntityId, + market: "CA" + ) + ).Value.Deserialize(_jsonOptions); + + List albums = result?.Result?.Items ?? + throw new TargetException($"No albums found for artist {e.artist}"); + + ExtractedResult match = Process.ExtractOne( + new ArtistAlbumItem { Name = e.album?.ToLower(_cultureInfo) }, + albums, + new Func((item) => + (item.Name ?? "").ToLower(_cultureInfo)) + ); + + uri = match.Value?.Uri ?? + throw new TargetException($"No matches found for album {e.album}"); + } + else + { + SpotifyplusSearchAlbumsResponse? result = ( + await services.Spotifyplus.SearchAlbumsAsync( + criteria: $"{e?.album}", + limitTotal: 1, + entityId: Globals.DefaultEntityId, + // My Defaults + market: "CA", + includeExternal: "audio" + ) + ).Value.Deserialize(_jsonOptions); + + uri = result?.Result?.Items?[0]?.Uri ?? + throw new TargetException( + $"The album {e?.album}{(e?.artist is null ? "" : $" by {e?.artist}")} could not be found." + ); + } + + services.Spotifyplus.PlayerMediaPlayContext( + contextUri: uri, + entityId: Globals.DefaultEntityId, + deviceId: Globals.DefaultDevId, + // My Defaults + positionMs: 0, + delay: 0.50 + ); + } + public PlayAlbum(IHaContext ha, Services services) { ha.RegisterServiceCallBack( "spotify_play_album", - async (e) => - { - try - { - string uri; - - if (e.artist is not null && e.artist != "") - { - SpotifyplusSearchArtistsResponse? artistResult = ( - await services.Spotifyplus.SearchArtistsAsync( - criteria: e?.artist ?? - throw new TargetException($"The artist {e?.artist} could not be found."), - limitTotal: 1, - entityId: Globals.DefaultEntityId, - // My Defaults - market: "CA", - includeExternal: "audio" - ) - ).Value.Deserialize(_jsonOptions); - - string artistId = artistResult?.Result?.Items?[0]?.Id ?? - throw new TargetException($"The artist {e?.artist} could not be found."); - - SpotifyPlusGetArtistAlbumsResponse? result = ( - await services.Spotifyplus.GetArtistAlbumsAsync( - artistId: artistId, - entityId: Globals.DefaultEntityId, - market: "CA" - ) - ).Value.Deserialize(_jsonOptions); - - List albums = result?.Result?.Items ?? - throw new TargetException($"No albums found for artist {e.artist}"); - - ExtractedResult match = Process.ExtractOne( - new ArtistAlbumItem { Name = e.album?.ToLower(_cultureInfo) }, - albums, - new Func((item) => - (item.Name ?? "").ToLower(_cultureInfo)) - ); - - uri = match.Value?.Uri ?? - throw new TargetException($"No matches found for album {e.album}"); - } - else - { - SpotifyplusSearchAlbumsResponse? result = ( - await services.Spotifyplus.SearchAlbumsAsync( - criteria: $"{e?.album}", - limitTotal: 1, - entityId: Globals.DefaultEntityId, - // My Defaults - market: "CA", - includeExternal: "audio" - ) - ).Value.Deserialize(_jsonOptions); - - uri = result?.Result?.Items?[0]?.Uri ?? - throw new TargetException( - $"The album {e?.album}{(e?.artist is null ? "" : $" by {e?.artist}")} could not be found." - ); - } - - services.Spotifyplus.PlayerMediaPlayContext( - contextUri: uri, - entityId: Globals.DefaultEntityId, - deviceId: Globals.DefaultDevId, - // My Defaults - positionMs: 0, - delay: 0.50 - ); - } - catch (Exception error) - { - services.Notify.PersistentNotification( - message: error.Message + "\n" + e.ToString(), - title: "Erreur Spotify"); - } - } + (e) => Globals.RunAsyncSpotifyCallback(services, e, CallBack) ); } } diff --git a/configurations/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayArtist/PlayArtist.cs b/configurations/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayArtist/PlayArtist.cs index cb990ae4..ad842510 100644 --- a/configurations/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayArtist/PlayArtist.cs +++ b/configurations/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayArtist/PlayArtist.cs @@ -1,6 +1,6 @@ -using System; using System.Reflection; using System.Text.Json; +using System.Threading.Tasks; using HomeAssistantGenerated; @@ -24,44 +24,37 @@ namespace NetDaemonConfig.Apps.Spotify.PlayArtist PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower }; + private async Task CallBack(PlayArtistData e, Services services) + { + SpotifyplusSearchArtistsResponse? result = ( + await services.Spotifyplus.SearchArtistsAsync( + criteria: e?.artist ?? throw new TargetException($"The artist {e?.artist} could not be found."), + limitTotal: 1, + entityId: Globals.DefaultEntityId, + // My Defaults + market: "CA", + includeExternal: "audio" + ) + ).Value.Deserialize(_jsonOptions); + + string uri = result?.Result?.Items?[0]?.Uri ?? + throw new TargetException($"The artist {e?.artist} could not be found."); + + services.Spotifyplus.PlayerMediaPlayContext( + contextUri: uri, + entityId: Globals.DefaultEntityId, + deviceId: Globals.DefaultDevId, + // My Defaults + positionMs: 0, + delay: 0.50 + ); + } + public PlayArtist(IHaContext ha, Services services) { ha.RegisterServiceCallBack( "spotify_play_artist", - async (e) => - { - try - { - SpotifyplusSearchArtistsResponse? result = ( - await services.Spotifyplus.SearchArtistsAsync( - criteria: e?.artist ?? throw new TargetException($"The artist {e?.artist} could not be found."), - limitTotal: 1, - entityId: Globals.DefaultEntityId, - // My Defaults - market: "CA", - includeExternal: "audio" - ) - ).Value.Deserialize(_jsonOptions); - - string uri = result?.Result?.Items?[0]?.Uri ?? - throw new TargetException($"The artist {e?.artist} could not be found."); - - services.Spotifyplus.PlayerMediaPlayContext( - contextUri: uri, - entityId: Globals.DefaultEntityId, - deviceId: Globals.DefaultDevId, - // My Defaults - positionMs: 0, - delay: 0.50 - ); - } - catch (Exception error) - { - services.Notify.PersistentNotification( - message: error.Message + "\n" + e.ToString(), - title: "Erreur Spotify"); - } - } + (e) => Globals.RunAsyncSpotifyCallback(services, e, CallBack) ); } } diff --git a/configurations/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayPlaylist/PlayPlaylist.cs b/configurations/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayPlaylist/PlayPlaylist.cs index e7bd0aa0..d5e6993c 100644 --- a/configurations/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayPlaylist/PlayPlaylist.cs +++ b/configurations/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayPlaylist/PlayPlaylist.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.Reflection; using System.Text.Json; +using System.Threading.Tasks; using FuzzySharp; using FuzzySharp.Extractor; @@ -31,71 +32,64 @@ namespace NetDaemonConfig.Apps.Spotify.PlayPlaylist PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower }; + private async Task CallBack(PlayPlaylistData e, Services services) + { + string query = e?.playlist ?? throw new TargetException("Query not found."); + + SpotifyplusPlaylistResponse? result = ( + await services.Spotifyplus.GetPlaylistFavoritesAsync( + limitTotal: 200, + sortResult: true, + entityId: Globals.DefaultEntityId + ) + ).Value.Deserialize(_jsonOptions); + + List myPlaylists = result?.Result?.Items ?? + throw new TargetException($"No playlists found for query {query}"); + + ExtractedResult match = Process.ExtractOne( + new PlaylistsItem { Name = query.ToLower(_cultureInfo) }, + myPlaylists, + new Func((item) => (item.Name ?? "").ToLower(_cultureInfo)) + ); + + string uri = match.Value?.Uri ?? throw new TargetException($"No matches found for query {query}"); + + // We search outside the user's playlists if the score is too low + if (match.Score < 85) + { + SpotifyplusPlaylistResponse? otherResult = ( + await services.Spotifyplus.SearchPlaylistsAsync( + criteria: query, + limitTotal: 1, + entityId: Globals.DefaultEntityId, + // My Defaults + market: "CA", + includeExternal: "audio" + ) + ).Value.Deserialize(_jsonOptions); + + string potentialUri = otherResult?.Result?.Items?[0]?.Uri ?? + throw new TargetException($"No public matches found for query {query}"); + + uri = potentialUri; + } + + services.Spotifyplus.PlayerMediaPlayContext( + contextUri: uri, + entityId: Globals.DefaultEntityId, + deviceId: Globals.DefaultDevId, + // My Defaults + positionMs: 0, + delay: 0.50 + ); + } + public PlayPlaylist(IHaContext ha, Services services) { ha.RegisterServiceCallBack( "spotify_play_playlist", - async (e) => - { - try - { - string query = e?.playlist ?? throw new TargetException("Query not found."); - - SpotifyplusPlaylistResponse? result = ( - await services.Spotifyplus.GetPlaylistFavoritesAsync( - limitTotal: 200, - sortResult: true, - entityId: Globals.DefaultEntityId - ) - ).Value.Deserialize(_jsonOptions); - - List myPlaylists = result?.Result?.Items ?? - throw new TargetException($"No playlists found for query {query}"); - - ExtractedResult match = Process.ExtractOne( - new PlaylistsItem { Name = query.ToLower(_cultureInfo) }, - myPlaylists, - new Func((item) => (item.Name ?? "").ToLower(_cultureInfo)) - ); - - string uri = match.Value?.Uri ?? throw new TargetException($"No matches found for query {query}"); - - // We search outside the user's playlists if the score is too low - if (match.Score < 85) - { - SpotifyplusPlaylistResponse? otherResult = ( - await services.Spotifyplus.SearchPlaylistsAsync( - criteria: query, - limitTotal: 1, - entityId: Globals.DefaultEntityId, - // My Defaults - market: "CA", - includeExternal: "audio" - ) - ).Value.Deserialize(_jsonOptions); - - string potentialUri = otherResult?.Result?.Items?[0]?.Uri ?? - throw new TargetException($"No public matches found for query {query}"); - - uri = potentialUri; - } - - services.Spotifyplus.PlayerMediaPlayContext( - contextUri: uri, - entityId: Globals.DefaultEntityId, - deviceId: Globals.DefaultDevId, - // My Defaults - positionMs: 0, - delay: 0.50 - ); - } - catch (Exception error) - { - services.Notify.PersistentNotification( - message: error.Message + "\n" + e.ToString(), - title: "Erreur Spotify"); - } - } + (e) => Globals.RunAsyncSpotifyCallback(services, e, CallBack) ); } } diff --git a/configurations/homie/modules/home-assistant/netdaemon/apps/Spotify/PlaySong/PlaySong.cs b/configurations/homie/modules/home-assistant/netdaemon/apps/Spotify/PlaySong/PlaySong.cs index 5a4eced2..b53a2c9c 100644 --- a/configurations/homie/modules/home-assistant/netdaemon/apps/Spotify/PlaySong/PlaySong.cs +++ b/configurations/homie/modules/home-assistant/netdaemon/apps/Spotify/PlaySong/PlaySong.cs @@ -1,6 +1,6 @@ -using System; using System.Reflection; using System.Text.Json; +using System.Threading.Tasks; using HomeAssistantGenerated; @@ -24,45 +24,38 @@ namespace NetDaemonConfig.Apps.Spotify.PlaySong PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower }; + private async Task CallBack(PlaySongData e, Services services) + { + SpotifyplusSearchTracksResponse? result = ( + await services.Spotifyplus.SearchTracksAsync( + criteria: $"{e?.artist} {e?.song}", + limitTotal: 1, + entityId: Globals.DefaultEntityId, + // My Defaults + market: "CA", + includeExternal: "audio" + ) + ).Value.Deserialize(_jsonOptions); + + string uri = result?.Result?.Items?[0]?.Uri ?? throw new TargetException( + $"The song {e?.song}{(e?.artist is null ? "" : $" by {e?.artist}")} could not be found." + ); + + services.Spotifyplus.PlayerMediaPlayTracks( + uris: uri, + entityId: Globals.DefaultEntityId, + deviceId: Globals.DefaultDevId, + // My Defaults + positionMs: 0, + delay: 0.50 + ); + } + public PlaySong(IHaContext ha, Services services) { ha.RegisterServiceCallBack( "spotify_play_song", - async (e) => - { - try - { - SpotifyplusSearchTracksResponse? result = ( - await services.Spotifyplus.SearchTracksAsync( - criteria: $"{e?.artist} {e?.song}", - limitTotal: 1, - entityId: Globals.DefaultEntityId, - // My Defaults - market: "CA", - includeExternal: "audio" - ) - ).Value.Deserialize(_jsonOptions); - - string uri = result?.Result?.Items?[0]?.Uri ?? throw new TargetException( - $"The song {e?.song}{(e?.artist is null ? "" : $" by {e?.artist}")} could not be found." - ); - - services.Spotifyplus.PlayerMediaPlayTracks( - uris: uri, - entityId: Globals.DefaultEntityId, - deviceId: Globals.DefaultDevId, - // My Defaults - positionMs: 0, - delay: 0.50 - ); - } - catch (Exception error) - { - services.Notify.PersistentNotification( - message: error.Message + "\n" + e.ToString(), - title: "Erreur Spotify"); - } - } + (e) => Globals.RunAsyncSpotifyCallback(services, e, CallBack) ); } } diff --git a/configurations/homie/modules/home-assistant/netdaemon/apps/Spotify/Types/Main.cs b/configurations/homie/modules/home-assistant/netdaemon/apps/Spotify/Types/Main.cs index b67ee637..1a79feba 100644 --- a/configurations/homie/modules/home-assistant/netdaemon/apps/Spotify/Types/Main.cs +++ b/configurations/homie/modules/home-assistant/netdaemon/apps/Spotify/Types/Main.cs @@ -1,4 +1,8 @@ +using System; using System.Collections.Generic; +using System.Threading.Tasks; + +using HomeAssistantGenerated; namespace NetDaemonConfig.Apps.Spotify.Types { @@ -6,6 +10,60 @@ namespace NetDaemonConfig.Apps.Spotify.Types { public const string DefaultDevId = "homie"; public const string DefaultEntityId = "media_player.spotifyplus"; + + public static void LogExceptions(Services services, Action callback, string extraInfo) + { + try + { + callback(); + } + catch (Exception error) + { + services.Notify.PersistentNotification( + message: error.Message + "\n" + extraInfo, + title: "Erreur Spotify"); + } + } + + public static void RunSpotifyCallback(Services services, Params e, Action callback) + { + void Callable() { callback(e, services); } + + // I do this because SpotifyPlus sometimes takes a failed call to successfully reach the speaker + try { Callable(); } + catch (Exception error) + { + Console.WriteLine(error.ToString()); + LogExceptions(services, Callable, e?.ToString() ?? ""); + } + } + + public static async void LogAsyncExceptions(Services services, Func callback, string extraInfo) + { + try + { + await callback(); + } + catch (Exception error) + { + services.Notify.PersistentNotification( + message: error.Message + "\n" + extraInfo, + title: "Erreur Spotify"); + } + } + + public static async void RunAsyncSpotifyCallback(Services services, Params e, Func callback) + { + async Task Callable() { await callback(e, services); } + + // I do this because SpotifyPlus sometimes takes a failed call to successfully reach the speaker + try { await Callable(); } + catch (Exception error) + { + Console.WriteLine(error.ToString()); + LogAsyncExceptions(services, Callable, e?.ToString() ?? ""); + } + } } // https://jsonformatter.org/yaml-to-json