feat(netd): improve album search
All checks were successful
Discord / discord commits (push) Has been skipped

This commit is contained in:
matt1432 2024-12-18 19:25:22 -05:00
parent d563c80bd0
commit 61dc9826b9
12 changed files with 137 additions and 36 deletions

View file

@ -6,6 +6,8 @@ using NetDaemon.AppModel;
using NetDaemon.HassModel; using NetDaemon.HassModel;
using NetDaemon.HassModel.Integration; using NetDaemon.HassModel.Integration;
using NetDaemonConfig.Apps.Spotify.Types;
namespace NetDaemonConfig.Apps.Spotify.PauseUnpause namespace NetDaemonConfig.Apps.Spotify.PauseUnpause
{ {
@ -25,14 +27,14 @@ namespace NetDaemonConfig.Apps.Spotify.PauseUnpause
if (e.pause) if (e.pause)
{ {
services.Spotifyplus.PlayerMediaPause( services.Spotifyplus.PlayerMediaPause(
entityId: SpotifyTypes.DefaultEntityId, entityId: Globals.DefaultEntityId,
deviceId: SpotifyTypes.DefaultDevId); deviceId: Globals.DefaultDevId);
} }
else else
{ {
services.Spotifyplus.PlayerMediaResume( services.Spotifyplus.PlayerMediaResume(
entityId: SpotifyTypes.DefaultEntityId, entityId: Globals.DefaultEntityId,
deviceId: SpotifyTypes.DefaultDevId); deviceId: Globals.DefaultDevId);
} }
} }
catch (Exception error) catch (Exception error)

View file

@ -1,13 +1,20 @@
using System; using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection; using System.Reflection;
using System.Text.Json; using System.Text.Json;
using FuzzySharp;
using FuzzySharp.Extractor;
using HomeAssistantGenerated; using HomeAssistantGenerated;
using NetDaemon.AppModel; using NetDaemon.AppModel;
using NetDaemon.HassModel; using NetDaemon.HassModel;
using NetDaemon.HassModel.Integration; using NetDaemon.HassModel.Integration;
using NetDaemonConfig.Apps.Spotify.Types;
namespace NetDaemonConfig.Apps.Spotify.PlayAlbum namespace NetDaemonConfig.Apps.Spotify.PlayAlbum
{ {
@ -16,6 +23,8 @@ namespace NetDaemonConfig.Apps.Spotify.PlayAlbum
[NetDaemonApp] [NetDaemonApp]
public class PlayAlbum public class PlayAlbum
{ {
private readonly CultureInfo _cultureInfo = new("fr-CA", false);
// Snake-case json options // Snake-case json options
private readonly JsonSerializerOptions _jsonOptions = new() private readonly JsonSerializerOptions _jsonOptions = new()
{ {
@ -30,26 +39,69 @@ namespace NetDaemonConfig.Apps.Spotify.PlayAlbum
{ {
try try
{ {
SpotifyplusSearchAlbumsResponse? result = ( string uri;
await services.Spotifyplus.SearchAlbumsAsync(
criteria: $"{e?.artist} {e?.album}",
limitTotal: 1,
entityId: SpotifyTypes.DefaultEntityId,
// My Defaults
market: "CA",
includeExternal: "audio"
)
).Value.Deserialize<SpotifyplusSearchAlbumsResponse>(_jsonOptions);
string uri = result?.Result?.Items?[0]?.Uri ?? if (e.artist is not null)
throw new TargetException( {
$"The album {e?.album}{(e?.artist is null ? "" : $" by {e?.artist}")} could not be found." 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<SpotifyplusSearchArtistsResponse>(_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<SpotifyPlusGetArtistAlbumsResponse>(_jsonOptions);
List<ArtistAlbumItem> albums = result?.Result?.Items ??
throw new TargetException($"No albums found for artist {e.artist}");
ExtractedResult<ArtistAlbumItem> match = Process.ExtractOne(
new ArtistAlbumItem { Name = e.album?.ToLower(_cultureInfo) },
albums,
new Func<ArtistAlbumItem, string>((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<SpotifyplusSearchAlbumsResponse>(_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( services.Spotifyplus.PlayerMediaPlayContext(
contextUri: uri, contextUri: uri,
entityId: SpotifyTypes.DefaultEntityId, entityId: Globals.DefaultEntityId,
deviceId: SpotifyTypes.DefaultDevId, deviceId: Globals.DefaultDevId,
// My Defaults // My Defaults
positionMs: 0, positionMs: 0,
delay: 0.50 delay: 0.50

View file

@ -8,6 +8,8 @@ using NetDaemon.AppModel;
using NetDaemon.HassModel; using NetDaemon.HassModel;
using NetDaemon.HassModel.Integration; using NetDaemon.HassModel.Integration;
using NetDaemonConfig.Apps.Spotify.Types;
namespace NetDaemonConfig.Apps.Spotify.PlayArtist namespace NetDaemonConfig.Apps.Spotify.PlayArtist
{ {
@ -34,7 +36,7 @@ namespace NetDaemonConfig.Apps.Spotify.PlayArtist
await services.Spotifyplus.SearchArtistsAsync( await services.Spotifyplus.SearchArtistsAsync(
criteria: e?.artist ?? throw new TargetException($"The artist {e?.artist} could not be found."), criteria: e?.artist ?? throw new TargetException($"The artist {e?.artist} could not be found."),
limitTotal: 1, limitTotal: 1,
entityId: SpotifyTypes.DefaultEntityId, entityId: Globals.DefaultEntityId,
// My Defaults // My Defaults
market: "CA", market: "CA",
includeExternal: "audio" includeExternal: "audio"
@ -46,8 +48,8 @@ namespace NetDaemonConfig.Apps.Spotify.PlayArtist
services.Spotifyplus.PlayerMediaPlayContext( services.Spotifyplus.PlayerMediaPlayContext(
contextUri: uri, contextUri: uri,
entityId: SpotifyTypes.DefaultEntityId, entityId: Globals.DefaultEntityId,
deviceId: SpotifyTypes.DefaultDevId, deviceId: Globals.DefaultDevId,
// My Defaults // My Defaults
positionMs: 0, positionMs: 0,
delay: 0.50 delay: 0.50

View file

@ -13,6 +13,8 @@ using NetDaemon.AppModel;
using NetDaemon.HassModel; using NetDaemon.HassModel;
using NetDaemon.HassModel.Integration; using NetDaemon.HassModel.Integration;
using NetDaemonConfig.Apps.Spotify.Types;
namespace NetDaemonConfig.Apps.Spotify.PlayPlaylist namespace NetDaemonConfig.Apps.Spotify.PlayPlaylist
{ {
@ -43,7 +45,7 @@ namespace NetDaemonConfig.Apps.Spotify.PlayPlaylist
await services.Spotifyplus.GetPlaylistFavoritesAsync( await services.Spotifyplus.GetPlaylistFavoritesAsync(
limitTotal: 200, limitTotal: 200,
sortResult: true, sortResult: true,
entityId: SpotifyTypes.DefaultEntityId entityId: Globals.DefaultEntityId
) )
).Value.Deserialize<SpotifyplusPlaylistResponse>(_jsonOptions); ).Value.Deserialize<SpotifyplusPlaylistResponse>(_jsonOptions);
@ -65,7 +67,7 @@ namespace NetDaemonConfig.Apps.Spotify.PlayPlaylist
await services.Spotifyplus.SearchPlaylistsAsync( await services.Spotifyplus.SearchPlaylistsAsync(
criteria: query, criteria: query,
limitTotal: 1, limitTotal: 1,
entityId: SpotifyTypes.DefaultEntityId, entityId: Globals.DefaultEntityId,
// My Defaults // My Defaults
market: "CA", market: "CA",
includeExternal: "audio" includeExternal: "audio"
@ -80,8 +82,8 @@ namespace NetDaemonConfig.Apps.Spotify.PlayPlaylist
services.Spotifyplus.PlayerMediaPlayContext( services.Spotifyplus.PlayerMediaPlayContext(
contextUri: uri, contextUri: uri,
entityId: SpotifyTypes.DefaultEntityId, entityId: Globals.DefaultEntityId,
deviceId: SpotifyTypes.DefaultDevId, deviceId: Globals.DefaultDevId,
// My Defaults // My Defaults
positionMs: 0, positionMs: 0,
delay: 0.50 delay: 0.50

View file

@ -8,6 +8,8 @@ using NetDaemon.AppModel;
using NetDaemon.HassModel; using NetDaemon.HassModel;
using NetDaemon.HassModel.Integration; using NetDaemon.HassModel.Integration;
using NetDaemonConfig.Apps.Spotify.Types;
namespace NetDaemonConfig.Apps.Spotify.PlaySong namespace NetDaemonConfig.Apps.Spotify.PlaySong
{ {
@ -34,7 +36,7 @@ namespace NetDaemonConfig.Apps.Spotify.PlaySong
await services.Spotifyplus.SearchTracksAsync( await services.Spotifyplus.SearchTracksAsync(
criteria: $"{e?.artist} {e?.song}", criteria: $"{e?.artist} {e?.song}",
limitTotal: 1, limitTotal: 1,
entityId: SpotifyTypes.DefaultEntityId, entityId: Globals.DefaultEntityId,
// My Defaults // My Defaults
market: "CA", market: "CA",
includeExternal: "audio" includeExternal: "audio"
@ -47,8 +49,8 @@ namespace NetDaemonConfig.Apps.Spotify.PlaySong
services.Spotifyplus.PlayerMediaPlayTracks( services.Spotifyplus.PlayerMediaPlayTracks(
uris: uri, uris: uri,
entityId: SpotifyTypes.DefaultEntityId, entityId: Globals.DefaultEntityId,
deviceId: SpotifyTypes.DefaultDevId, deviceId: Globals.DefaultDevId,
// My Defaults // My Defaults
positionMs: 0, positionMs: 0,
delay: 0.50 delay: 0.50

View file

@ -0,0 +1,42 @@
using System.Collections.Generic;
namespace NetDaemonConfig.Apps.Spotify.Types
{
public record ArtistAlbumItem
{
public string? AlbumType { get; set; }
public List<Artist>? Artists { get; set; }
public List<object>? AvailableMarkets { get; set; }
public ExternalUrls? ExternalUrls { get; set; }
public string? Href { get; set; }
public string? Id { get; set; }
public string? ImageUrl { get; set; }
public List<Image>? Images { get; set; }
public string? Name { get; set; }
public string? ReleaseDate { get; set; }
public string? ReleaseDatePrecision { get; set; }
public Restrictions? Restrictions { get; set; }
public int? TotalTracks { get; set; }
public string? Type { get; set; }
public string? Uri { get; set; }
}
public record ArtistAlbumResult
{
public double? DateLastRefreshed { get; set; }
public string? Href { get; set; }
public int? Limit { get; set; }
public object? Next { get; set; }
public int? Offset { get; set; }
public object? Previous { get; set; }
public int? Total { get; set; }
public List<ArtistAlbumItem>? Items { get; set; }
}
public record SpotifyPlusGetArtistAlbumsResponse
{
public UserProfile? UserProfile { get; set; }
public ArtistAlbumResult? Result { get; set; }
}
}

View file

@ -1,8 +1,8 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace NetDaemonConfig.Apps.Spotify namespace NetDaemonConfig.Apps.Spotify.Types
{ {
public static class SpotifyTypes public static class Globals
{ {
public const string DefaultDevId = "homie"; public const string DefaultDevId = "homie";
public const string DefaultEntityId = "media_player.spotifyplus"; public const string DefaultEntityId = "media_player.spotifyplus";

View file

@ -1,7 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace NetDaemonConfig.Apps.Spotify.PlayPlaylist namespace NetDaemonConfig.Apps.Spotify.Types
{ {
public record PlaylistsItem public record PlaylistsItem
{ {

View file

@ -1,7 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace NetDaemonConfig.Apps.Spotify.PlayAlbum namespace NetDaemonConfig.Apps.Spotify.Types
{ {
public record AlbumItem public record AlbumItem
{ {

View file

@ -1,7 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace NetDaemonConfig.Apps.Spotify.PlayArtist namespace NetDaemonConfig.Apps.Spotify.Types
{ {
public record ArtistItem public record ArtistItem
{ {

View file

@ -1,7 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace NetDaemonConfig.Apps.Spotify.PlaySong namespace NetDaemonConfig.Apps.Spotify.Types
{ {
public record SongItem public record SongItem
{ {

View file

@ -35,7 +35,6 @@ in {
end, end,
}); });
-- FIXME: make editorconfig and format work
require('roslyn').setup({ require('roslyn').setup({
config = { config = {
capabilities = require('cmp_nvim_lsp').default_capabilities(), capabilities = require('cmp_nvim_lsp').default_capabilities(),