From b6c7d203bfed18452dd8998772284e2791818e31 Mon Sep 17 00:00:00 2001 From: matt1432 Date: Thu, 31 Oct 2024 23:13:02 -0400 Subject: [PATCH] feat(netd nvim): switch to omnisharp and add linter --- common/home/neovim/langs/csharp.nix | 38 +- .../home-assistant/netdaemon/.editorconfig | 360 ++++++++++++++++++ .../Apps/Spotify/PlayAlbum/PlayAlbum.cs | 68 ++++ .../SpotifyplusSearchAlbumsResponse.cs | 41 ++ .../Apps/Spotify/PlayArtist/PlayArtist.cs | 66 ++++ .../SpotifyplusSearchArtistsResponse.cs | 37 ++ .../Apps/Spotify/PlayPlaylist/PlayPlaylist.cs | 100 +++++ .../SpotifyplusPlaylistResponse.cs | 40 ++ .../Apps/Spotify/PlaySong/PlaySong.cs | 67 ++++ .../SpotifyplusSearchTracksResponse.cs | 46 +++ .../netdaemon/Apps/Spotify/Types.cs | 102 +++++ .../apps/Spotify/PlayAlbum/PlayAlbum.cs | 62 --- .../SpotifyplusSearchAlbumsResponse.cs | 40 -- .../apps/Spotify/PlayArtist/PlayArtist.cs | 60 --- .../SpotifyplusSearchArtistsResponse.cs | 36 -- .../apps/Spotify/PlayPlaylist/PlayPlaylist.cs | 89 ----- .../SpotifyplusPlaylistResponse.cs | 39 -- .../apps/Spotify/PlaySong/PlaySong.cs | 60 --- .../SpotifyplusSearchTracksResponse.cs | 44 --- .../netdaemon/apps/Spotify/Types.cs | 103 ----- .../home-assistant/netdaemon/netdaemon.csproj | 3 +- .../home-assistant/netdaemon/program.cs | 13 +- 22 files changed, 966 insertions(+), 548 deletions(-) create mode 100644 devices/homie/modules/home-assistant/netdaemon/.editorconfig create mode 100644 devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlayAlbum/PlayAlbum.cs create mode 100644 devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlayAlbum/SpotifyplusSearchAlbumsResponse.cs create mode 100644 devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlayArtist/PlayArtist.cs create mode 100644 devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlayArtist/SpotifyplusSearchArtistsResponse.cs create mode 100644 devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlayPlaylist/PlayPlaylist.cs create mode 100644 devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlayPlaylist/SpotifyplusPlaylistResponse.cs create mode 100644 devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlaySong/PlaySong.cs create mode 100644 devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlaySong/SpotifyplusSearchTracksResponse.cs create mode 100644 devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/Types.cs delete mode 100644 devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayAlbum/PlayAlbum.cs delete mode 100644 devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayAlbum/SpotifyplusSearchAlbumsResponse.cs delete mode 100644 devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayArtist/PlayArtist.cs delete mode 100644 devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayArtist/SpotifyplusSearchArtistsResponse.cs delete mode 100644 devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayPlaylist/PlayPlaylist.cs delete mode 100644 devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayPlaylist/SpotifyplusPlaylistResponse.cs delete mode 100644 devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlaySong/PlaySong.cs delete mode 100644 devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlaySong/SpotifyplusSearchTracksResponse.cs delete mode 100644 devices/homie/modules/home-assistant/netdaemon/apps/Spotify/Types.cs diff --git a/common/home/neovim/langs/csharp.nix b/common/home/neovim/langs/csharp.nix index 1cb4d7bf..d1669d10 100644 --- a/common/home/neovim/langs/csharp.nix +++ b/common/home/neovim/langs/csharp.nix @@ -13,7 +13,7 @@ in extraPackages = builtins.attrValues { inherit (pkgs) - csharp-ls + omnisharp-roslyn ; }; @@ -21,23 +21,45 @@ in # lua '' vim.api.nvim_create_autocmd('FileType', { - pattern = {'cs'}, + pattern = { 'cs' }, command = 'setlocal ts=4 sw=4 sts=0 expandtab', }); - local csharpls_extended = require('csharpls_extended'); + local omnisharp_extended = require('omnisharp_extended'); + + require('lspconfig').omnisharp.setup({ + cmd = { "dotnet", "${pkgs.omnisharp-roslyn}/lib/omnisharp-roslyn/OmniSharp.dll" }, - require('lspconfig').csharp_ls.setup({ - capabilities = require('cmp_nvim_lsp').default_capabilities(), handlers = { - ["textDocument/definition"] = csharpls_extended.handler, - ["textDocument/typeDefinition"] = csharpls_extended.handler, + ["textDocument/definition"] = omnisharp_extended.definition_handler, + ["textDocument/typeDefinition"] = omnisharp_extended.type_definition_handler, + ["textDocument/references"] = omnisharp_extended.references_handler, + ["textDocument/implementation"] = omnisharp_extended.implementation_handler, + }, + + settings = { + FormattingOptions = { + EnableEditorConfigSupport = true, + OrganizeImports = true, + }, + MsBuild = { + LoadProjectsOnDemand = false, + }, + RoslynExtensionsOptions = { + EnableAnalyzersSupport = true, + EnableDecompilationSupport = true, + EnableImportCompletion = true, + AnalyzeOpenDocumentsOnly = false, + }, + Sdk = { + IncludePrereleases = true, + }, }, }); ''; plugins = builtins.attrValues { - inherit (pkgs.vimPlugins) csharpls-extended-lsp-nvim; + inherit (pkgs.vimPlugins) omnisharp-extended-lsp-nvim; }; }; }; diff --git a/devices/homie/modules/home-assistant/netdaemon/.editorconfig b/devices/homie/modules/home-assistant/netdaemon/.editorconfig new file mode 100644 index 00000000..2e1b7d21 --- /dev/null +++ b/devices/homie/modules/home-assistant/netdaemon/.editorconfig @@ -0,0 +1,360 @@ +root = true + +# All files +[*] +indent_style = space + +# C# files +[*.cs] + +#### Core EditorConfig Options #### + +# Indentation and spacing +indent_size = 4 +tab_width = 4 + +# New line preferences +end_of_line = lf +insert_final_newline = true + +#### .NET Coding Conventions #### +[*.{cs,vb}] + +# Organize usings +dotnet_separate_import_directive_groups = true +dotnet_sort_system_directives_first = true +file_header_template = unset + +# this. and Me. preferences +dotnet_style_qualification_for_event = false:silent +dotnet_style_qualification_for_field = false:silent +dotnet_style_qualification_for_method = false:silent +dotnet_style_qualification_for_property = false:silent + +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true:silent +dotnet_style_predefined_type_for_member_access = true:silent + +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent + +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent + +# Expression-level preferences +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_object_initializer = true:suggestion +dotnet_style_operator_placement_when_wrapping = beginning_of_line +dotnet_style_prefer_auto_properties = true:suggestion +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_return = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_simplified_interpolation = true:suggestion + +# Field preferences +dotnet_style_readonly_field = true:warning + +# Parameter preferences +dotnet_code_quality_unused_parameters = all:suggestion + +# Suppression preferences +dotnet_remove_unnecessary_suppression_exclusions = none + +#### C# Coding Conventions #### +[*.cs] + +# var preferences +csharp_style_var_elsewhere = false:silent +csharp_style_var_for_built_in_types = false:silent +csharp_style_var_when_type_is_apparent = false:silent + +# Expression-bodied members +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_lambdas = true:suggestion +csharp_style_expression_bodied_local_functions = false:silent +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent + +# Pattern matching preferences +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_prefer_not_pattern = true:suggestion +csharp_style_prefer_pattern_matching = true:silent +csharp_style_prefer_switch_expression = true:suggestion + +# Null-checking preferences +csharp_style_conditional_delegate_call = true:suggestion + +# Modifier preferences +csharp_prefer_static_local_function = true:warning +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent + +# Code-block preferences +csharp_prefer_braces = true:silent +csharp_prefer_simple_using_statement = true:suggestion + +# Expression-level preferences +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_pattern_local_over_anonymous_function = true:suggestion +csharp_style_prefer_index_operator = true:suggestion +csharp_style_prefer_range_operator = true:suggestion +csharp_style_throw_expression = true:suggestion +csharp_style_unused_value_assignment_preference = discard_variable:suggestion +csharp_style_unused_value_expression_statement_preference = discard_variable:silent + +# 'using' directive preferences +csharp_using_directive_placement = outside_namespace:silent + +#### C# Formatting Rules #### + +# New line preferences +csharp_new_line_before_catch = true +csharp_new_line_before_else = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_open_brace = all +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_labels = one_less_than_current +csharp_indent_switch_labels = true + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Wrapping preferences +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true + +#### Naming styles #### +[*.{cs,vb}] + +# Naming rules + +dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.symbols = types_and_namespaces +dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.interfaces_should_be_ipascalcase.severity = suggestion +dotnet_naming_rule.interfaces_should_be_ipascalcase.symbols = interfaces +dotnet_naming_rule.interfaces_should_be_ipascalcase.style = ipascalcase + +dotnet_naming_rule.type_parameters_should_be_tpascalcase.severity = suggestion +dotnet_naming_rule.type_parameters_should_be_tpascalcase.symbols = type_parameters +dotnet_naming_rule.type_parameters_should_be_tpascalcase.style = tpascalcase + +dotnet_naming_rule.methods_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.methods_should_be_pascalcase.symbols = methods +dotnet_naming_rule.methods_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.properties_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.properties_should_be_pascalcase.symbols = properties +dotnet_naming_rule.properties_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.events_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.events_should_be_pascalcase.symbols = events +dotnet_naming_rule.events_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.local_variables_should_be_camelcase.severity = suggestion +dotnet_naming_rule.local_variables_should_be_camelcase.symbols = local_variables +dotnet_naming_rule.local_variables_should_be_camelcase.style = camelcase + +dotnet_naming_rule.local_constants_should_be_camelcase.severity = suggestion +dotnet_naming_rule.local_constants_should_be_camelcase.symbols = local_constants +dotnet_naming_rule.local_constants_should_be_camelcase.style = camelcase + +dotnet_naming_rule.parameters_should_be_camelcase.severity = suggestion +dotnet_naming_rule.parameters_should_be_camelcase.symbols = parameters +dotnet_naming_rule.parameters_should_be_camelcase.style = camelcase + +dotnet_naming_rule.public_fields_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.public_fields_should_be_pascalcase.symbols = public_fields +dotnet_naming_rule.public_fields_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.private_fields_should_be__camelcase.severity = suggestion +dotnet_naming_rule.private_fields_should_be__camelcase.symbols = private_fields +dotnet_naming_rule.private_fields_should_be__camelcase.style = _camelcase + +dotnet_naming_rule.private_static_fields_should_be_s_camelcase.severity = suggestion +dotnet_naming_rule.private_static_fields_should_be_s_camelcase.symbols = private_static_fields +dotnet_naming_rule.private_static_fields_should_be_s_camelcase.style = s_camelcase + +dotnet_naming_rule.public_constant_fields_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.public_constant_fields_should_be_pascalcase.symbols = public_constant_fields +dotnet_naming_rule.public_constant_fields_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.private_constant_fields_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.private_constant_fields_should_be_pascalcase.symbols = private_constant_fields +dotnet_naming_rule.private_constant_fields_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.symbols = public_static_readonly_fields +dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.symbols = private_static_readonly_fields +dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.enums_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.enums_should_be_pascalcase.symbols = enums +dotnet_naming_rule.enums_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.local_functions_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.local_functions_should_be_pascalcase.symbols = local_functions +dotnet_naming_rule.local_functions_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.non_field_members_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascalcase.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascalcase.style = pascalcase + +# Symbol specifications + +dotnet_naming_symbols.interfaces.applicable_kinds = interface +dotnet_naming_symbols.interfaces.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interfaces.required_modifiers = + +dotnet_naming_symbols.enums.applicable_kinds = enum +dotnet_naming_symbols.enums.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.enums.required_modifiers = + +dotnet_naming_symbols.events.applicable_kinds = event +dotnet_naming_symbols.events.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.events.required_modifiers = + +dotnet_naming_symbols.methods.applicable_kinds = method +dotnet_naming_symbols.methods.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.methods.required_modifiers = + +dotnet_naming_symbols.properties.applicable_kinds = property +dotnet_naming_symbols.properties.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.properties.required_modifiers = + +dotnet_naming_symbols.public_fields.applicable_kinds = field +dotnet_naming_symbols.public_fields.applicable_accessibilities = public, internal +dotnet_naming_symbols.public_fields.required_modifiers = + +dotnet_naming_symbols.private_fields.applicable_kinds = field +dotnet_naming_symbols.private_fields.applicable_accessibilities = private, protected, protected_internal, private_protected +dotnet_naming_symbols.private_fields.required_modifiers = + +dotnet_naming_symbols.private_static_fields.applicable_kinds = field +dotnet_naming_symbols.private_static_fields.applicable_accessibilities = private, protected, protected_internal, private_protected +dotnet_naming_symbols.private_static_fields.required_modifiers = static + +dotnet_naming_symbols.types_and_namespaces.applicable_kinds = namespace, class, struct, interface, enum +dotnet_naming_symbols.types_and_namespaces.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types_and_namespaces.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +dotnet_naming_symbols.type_parameters.applicable_kinds = namespace +dotnet_naming_symbols.type_parameters.applicable_accessibilities = * +dotnet_naming_symbols.type_parameters.required_modifiers = + +dotnet_naming_symbols.private_constant_fields.applicable_kinds = field +dotnet_naming_symbols.private_constant_fields.applicable_accessibilities = private, protected, protected_internal, private_protected +dotnet_naming_symbols.private_constant_fields.required_modifiers = const + +dotnet_naming_symbols.local_variables.applicable_kinds = local +dotnet_naming_symbols.local_variables.applicable_accessibilities = local +dotnet_naming_symbols.local_variables.required_modifiers = + +dotnet_naming_symbols.local_constants.applicable_kinds = local +dotnet_naming_symbols.local_constants.applicable_accessibilities = local +dotnet_naming_symbols.local_constants.required_modifiers = const + +dotnet_naming_symbols.parameters.applicable_kinds = parameter +dotnet_naming_symbols.parameters.applicable_accessibilities = * +dotnet_naming_symbols.parameters.required_modifiers = + +dotnet_naming_symbols.public_constant_fields.applicable_kinds = field +dotnet_naming_symbols.public_constant_fields.applicable_accessibilities = public, internal +dotnet_naming_symbols.public_constant_fields.required_modifiers = const + +dotnet_naming_symbols.public_static_readonly_fields.applicable_kinds = field +dotnet_naming_symbols.public_static_readonly_fields.applicable_accessibilities = public, internal +dotnet_naming_symbols.public_static_readonly_fields.required_modifiers = readonly, static + +dotnet_naming_symbols.private_static_readonly_fields.applicable_kinds = field +dotnet_naming_symbols.private_static_readonly_fields.applicable_accessibilities = private, protected, protected_internal, private_protected +dotnet_naming_symbols.private_static_readonly_fields.required_modifiers = readonly, static + +dotnet_naming_symbols.local_functions.applicable_kinds = local_function +dotnet_naming_symbols.local_functions.applicable_accessibilities = * +dotnet_naming_symbols.local_functions.required_modifiers = + +# Naming styles + +dotnet_naming_style.pascalcase.required_prefix = +dotnet_naming_style.pascalcase.required_suffix = +dotnet_naming_style.pascalcase.word_separator = +dotnet_naming_style.pascalcase.capitalization = pascal_case + +dotnet_naming_style.ipascalcase.required_prefix = I +dotnet_naming_style.ipascalcase.required_suffix = +dotnet_naming_style.ipascalcase.word_separator = +dotnet_naming_style.ipascalcase.capitalization = pascal_case + +dotnet_naming_style.tpascalcase.required_prefix = T +dotnet_naming_style.tpascalcase.required_suffix = +dotnet_naming_style.tpascalcase.word_separator = +dotnet_naming_style.tpascalcase.capitalization = pascal_case + +dotnet_naming_style._camelcase.required_prefix = _ +dotnet_naming_style._camelcase.required_suffix = +dotnet_naming_style._camelcase.word_separator = +dotnet_naming_style._camelcase.capitalization = camel_case + +dotnet_naming_style.camelcase.required_prefix = +dotnet_naming_style.camelcase.required_suffix = +dotnet_naming_style.camelcase.word_separator = +dotnet_naming_style.camelcase.capitalization = camel_case + +dotnet_naming_style.s_camelcase.required_prefix = s_ +dotnet_naming_style.s_camelcase.required_suffix = +dotnet_naming_style.s_camelcase.word_separator = +dotnet_naming_style.s_camelcase.capitalization = camel_case + diff --git a/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlayAlbum/PlayAlbum.cs b/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlayAlbum/PlayAlbum.cs new file mode 100644 index 00000000..89f8df4c --- /dev/null +++ b/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlayAlbum/PlayAlbum.cs @@ -0,0 +1,68 @@ +using System; +using System.Reflection; +using System.Text.Json; + +using HomeAssistantGenerated; + +using NetDaemon.AppModel; +using NetDaemon.HassModel; +using NetDaemon.HassModel.Integration; + + +namespace NetDaemonConfig.Apps.Spotify.PlayAlbum +{ + public record PlayAlbumData(string? Artist, string? Album); + + [NetDaemonApp] + public class PlayAlbum + { + // Snake-case json options + private readonly JsonSerializerOptions _jsonOptions = new() + { + PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower + }; + + public PlayAlbum(IHaContext ha, Services services) + { + ha.RegisterServiceCallBack( + "spotify_play_album", + async (e) => + { + try + { + SpotifyplusSearchAlbumsResponse? result = ( + await services.Spotifyplus.SearchAlbumsAsync( + criteria: $"{e?.Artist} {e?.Album}", + limitTotal: 1, + entityId: SpotifyTypes.DefaultEntityId, + // My Defaults + market: "CA", + includeExternal: "audio" + ) + ).Value.Deserialize(_jsonOptions); + + string 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: SpotifyTypes.DefaultEntityId, + deviceId: SpotifyTypes.DefaultDevId, + // My Defaults + positionMs: 0, + delay: 0.50 + ); + } + catch (Exception error) + { + services.PersistentNotification.Create( + message: error.Message, + title: "Erreur Spotify"); + } + } + ); + } + } +} diff --git a/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlayAlbum/SpotifyplusSearchAlbumsResponse.cs b/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlayAlbum/SpotifyplusSearchAlbumsResponse.cs new file mode 100644 index 00000000..d35680af --- /dev/null +++ b/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlayAlbum/SpotifyplusSearchAlbumsResponse.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; + + +namespace NetDaemonConfig.Apps.Spotify.PlayAlbum +{ + public record AlbumItem + { + public string? AlbumType { get; set; } + public List? Artists { get; set; } + public List? 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? 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 AlbumResult + { + public string? Href { get; set; } + public int? Limit { get; set; } + public string? Next { get; set; } + public int? Offset { get; set; } + public object? Previous { get; set; } + public int? Total { get; set; } + public List? Items { get; set; } + } + + public record SpotifyplusSearchAlbumsResponse + { + public UserProfile? UserProfile { get; set; } + public AlbumResult? Result { get; set; } + } +} diff --git a/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlayArtist/PlayArtist.cs b/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlayArtist/PlayArtist.cs new file mode 100644 index 00000000..5f1864e6 --- /dev/null +++ b/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlayArtist/PlayArtist.cs @@ -0,0 +1,66 @@ +using System; +using System.Reflection; +using System.Text.Json; + +using HomeAssistantGenerated; + +using NetDaemon.AppModel; +using NetDaemon.HassModel; +using NetDaemon.HassModel.Integration; + + +namespace NetDaemonConfig.Apps.Spotify.PlayArtist +{ + public record PlayArtistData(string? Artist); + + [NetDaemonApp] + public class PlayArtist + { + // Snake-case json options + private readonly JsonSerializerOptions _jsonOptions = new() + { + PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower + }; + + 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: SpotifyTypes.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: SpotifyTypes.DefaultEntityId, + deviceId: SpotifyTypes.DefaultDevId, + // My Defaults + positionMs: 0, + delay: 0.50 + ); + } + catch (Exception error) + { + services.PersistentNotification.Create( + message: error.Message, + title: "Erreur Spotify"); + } + } + ); + } + } +} diff --git a/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlayArtist/SpotifyplusSearchArtistsResponse.cs b/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlayArtist/SpotifyplusSearchArtistsResponse.cs new file mode 100644 index 00000000..452dc5d3 --- /dev/null +++ b/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlayArtist/SpotifyplusSearchArtistsResponse.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; + + +namespace NetDaemonConfig.Apps.Spotify.PlayArtist +{ + public record ArtistItem + { + public ExternalUrls? ExternalUrls { get; init; } + public Followers? Followers { get; init; } + public List? Genres { get; init; } + public string? Href { get; init; } + public string? Id { get; init; } + public string? ImageUrl { get; init; } + public List? Images { get; init; } + public string? Name { get; init; } + public int? Popularity { get; init; } + public string? Type { get; init; } + public string? Uri { get; init; } + } + + public record ArtistResult + { + public string? Href { get; init; } + public int? Limit { get; init; } + public string? Next { get; init; } + public int? Offset { get; set; } + public object? Previous { get; init; } + public int? Total { get; init; } + public List? Items { get; init; } + } + + public record SpotifyplusSearchArtistsResponse + { + public UserProfile? UserProfile { get; init; } + public ArtistResult? Result { get; init; } + } +} diff --git a/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlayPlaylist/PlayPlaylist.cs b/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlayPlaylist/PlayPlaylist.cs new file mode 100644 index 00000000..f899b7b6 --- /dev/null +++ b/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlayPlaylist/PlayPlaylist.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Reflection; +using System.Text.Json; + +using FuzzySharp; +using FuzzySharp.Extractor; + +using HomeAssistantGenerated; + +using NetDaemon.AppModel; +using NetDaemon.HassModel; +using NetDaemon.HassModel.Integration; + + +namespace NetDaemonConfig.Apps.Spotify.PlayPlaylist +{ + public record PlayPlaylistData(string? Playlist); + + [NetDaemonApp] + public class PlayPlaylist + { + private readonly CultureInfo _cultureInfo = new("fr-CA", false); + + // Snake-case json options + private readonly JsonSerializerOptions _jsonOptions = new() + { + PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower + }; + + 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: SpotifyTypes.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: SpotifyTypes.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: SpotifyTypes.DefaultEntityId, + deviceId: SpotifyTypes.DefaultDevId, + // My Defaults + positionMs: 0, + delay: 0.50 + ); + } + catch (Exception error) + { + services.PersistentNotification.Create( + message: error.Message, + title: "Erreur Spotify"); + } + } + ); + } + } +} diff --git a/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlayPlaylist/SpotifyplusPlaylistResponse.cs b/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlayPlaylist/SpotifyplusPlaylistResponse.cs new file mode 100644 index 00000000..d5d9ab5c --- /dev/null +++ b/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlayPlaylist/SpotifyplusPlaylistResponse.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; + + +namespace NetDaemonConfig.Apps.Spotify.PlayPlaylist +{ + public record PlaylistsItem + { + public bool? Collaborative { get; set; } + public string? Description { get; set; } + public ExternalUrls? ExternalUrls { get; set; } + public string? Href { get; set; } + public string? Id { get; set; } + public string? ImageUrl { get; set; } + public List? Images { get; set; } + public string? Name { get; set; } + public Owner? Owner { get; set; } + public bool? Public { get; set; } + public string? SnapshotId { get; set; } + public Tracks? Tracks { get; set; } + public string? Type { get; set; } + public string? Uri { get; set; } + } + + public record PlaylistsResult + { + 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? Items { get; set; } + } + + public record SpotifyplusPlaylistResponse + { + public UserProfile? UserProfile { get; set; } + public PlaylistsResult? Result { get; set; } + } +} diff --git a/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlaySong/PlaySong.cs b/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlaySong/PlaySong.cs new file mode 100644 index 00000000..d2f78467 --- /dev/null +++ b/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlaySong/PlaySong.cs @@ -0,0 +1,67 @@ +using System; +using System.Text.Json; +using System.Reflection; + +using HomeAssistantGenerated; + +using NetDaemon.AppModel; +using NetDaemon.HassModel; +using NetDaemon.HassModel.Integration; + + +namespace NetDaemonConfig.Apps.Spotify.PlaySong +{ + public record PlaySongData(string? Artist, string? Song); + + [NetDaemonApp] + public class PlaySong + { + // Snake-case json options + private readonly JsonSerializerOptions _jsonOptions = new() + { + PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower + }; + + 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: SpotifyTypes.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: SpotifyTypes.DefaultEntityId, + deviceId: SpotifyTypes.DefaultDevId, + // My Defaults + positionMs: 0, + delay: 0.50 + ); + } + catch (Exception error) + { + services.PersistentNotification.Create( + message: error.Message, + title: "Erreur Spotify"); + } + } + ); + } + } +} diff --git a/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlaySong/SpotifyplusSearchTracksResponse.cs b/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlaySong/SpotifyplusSearchTracksResponse.cs new file mode 100644 index 00000000..049d740d --- /dev/null +++ b/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/PlaySong/SpotifyplusSearchTracksResponse.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; + + +namespace NetDaemonConfig.Apps.Spotify.PlaySong +{ + public record SongItem + { + public Album? Album { get; set; } + public List? Artists { get; set; } + public List? AvailableMarkets { get; set; } + public int? DiscNumber { get; set; } + public int? DurationMs { get; set; } + public bool? Explicit { get; set; } + public ExternalIds? ExternalIds { get; set; } + public ExternalUrls? ExternalUrls { get; set; } + public string? Href { get; set; } + public string? Id { get; set; } + public string? ImageUrl { get; set; } + public bool? IsLocal { get; set; } + public object? IsPlayable { get; set; } + public string? Name { get; set; } + public int? Popularity { get; set; } + public object? PreviewUrl { get; set; } + public Restrictions? Restrictions { get; set; } + public int? TrackNumber { get; set; } + public string? Type { get; set; } + public string? Uri { get; set; } + } + + public record SongResult + { + public string? Href { get; set; } + public int? Limit { get; set; } + public string? Next { get; set; } + public int? Offset { get; set; } + public object? Previous { get; set; } + public int? Total { get; set; } + public List? Items { get; set; } + } + + public record SpotifyplusSearchTracksResponse + { + public UserProfile? UserProfile { get; set; } + public SongResult? Result { get; set; } + } +} diff --git a/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/Types.cs b/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/Types.cs new file mode 100644 index 00000000..5ed7c70d --- /dev/null +++ b/devices/homie/modules/home-assistant/netdaemon/Apps/Spotify/Types.cs @@ -0,0 +1,102 @@ +using System.Collections.Generic; + +namespace NetDaemonConfig.Apps.Spotify +{ + public static class SpotifyTypes + { + public const string DefaultDevId = "homie connect"; + public const string DefaultEntityId = "media_player.spotifyplus"; + } + + // https://jsonformatter.org/yaml-to-json + // https://json2csharp.com + // https://github.com/thlucas1/homeassistantcomponent_spotifyplus/blob/master/custom_components/spotifyplus/services.yaml + public record Restrictions { } + + public record UserProfile + { + public string? Country { get; set; } + public string? DisplayName { get; set; } + public string? Email { get; set; } + public string? Id { get; set; } + public string? Product { get; set; } + public string? Type { get; set; } + public string? Uri { get; set; } + } + + public record ExternalUrls + { + public string? Spotify { get; set; } + } + + public record Followers + { + public string? Href { get; set; } + public int? Total { get; set; } + } + + public record Image + { + public string? Url { get; set; } + public int? Height { get; set; } + public int? Width { get; set; } + } + + public record Owner + { + public string? DisplayName { get; set; } + public ExternalUrls? ExternalUrls { get; set; } + public Followers? Followers { get; set; } + public string? Href { get; set; } + public string? Id { get; set; } + public string? Type { get; set; } + public string? Uri { get; set; } + } + + public record Tracks + { + public string? Href { get; set; } + public int? Total { get; set; } + } + + public record Artist + { + public ExternalUrls? ExternalUrls { get; set; } + public string? Href { get; set; } + public string? Id { get; set; } + public string? Name { get; set; } + public string? Type { get; set; } + public string? Uri { get; set; } + } + + public record ExternalIds + { + public object? Ean { get; set; } + public string? Isrc { get; set; } + public object? Upc { get; set; } + } + + public record Album + { + public string? AlbumType { get; set; } + public List? Artists { get; set; } + public List? AvailableMarkets { get; set; } + public List? Copyrights { get; set; } + public ExternalIds? ExternalIds { get; set; } + public ExternalUrls? ExternalUrls { get; set; } + public List? Genres { get; set; } + public string? Href { get; set; } + public string? Id { get; set; } + public string? ImageUrl { get; set; } + public List? Images { get; set; } + public object? Label { get; set; } + public string? Name { get; set; } + public object? Popularity { 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; } + } +} diff --git a/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayAlbum/PlayAlbum.cs b/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayAlbum/PlayAlbum.cs deleted file mode 100644 index 158bd2d6..00000000 --- a/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayAlbum/PlayAlbum.cs +++ /dev/null @@ -1,62 +0,0 @@ -namespace Spotify; - -using HomeAssistantGenerated; -using NetDaemon.AppModel; -using NetDaemon.HassModel; -using NetDaemon.HassModel.Integration; -using System; -using System.Text.Json; - -record PlayAlbumData(string? artist, string? album); - - -[NetDaemonApp] -public class PlayAlbum -{ - // Snake-case json options - private readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions - { - PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower - }; - - public PlayAlbum(IHaContext ha, Services services, Entities entities) - { - ha.RegisterServiceCallBack( - "spotify_play_album", - async (e) => - { - try - { - var result = (await services.Spotifyplus.SearchAlbumsAsync( - criteria: $"{e?.artist} {e?.album}", - limitTotal: 1, - entityId: Global.DEFAULT_ENTITY_ID, - // My Defaults - market: "CA", - includeExternal: "audio" - )).Value.Deserialize(_jsonOptions); - - string uri = result?.Result?.Items?[0]?.Uri ?? - throw new NullReferenceException( - $"The album {e?.album}{(e?.artist is null ? "" : $" by {e?.artist}")} could not be found." - ); - - services.Spotifyplus.PlayerMediaPlayContext( - contextUri: uri, - entityId: Global.DEFAULT_ENTITY_ID, - deviceId: Global.DEFAULT_DEV_ID, - // My Defaults - positionMs: 0, - delay: 0.50 - ); - } - catch (Exception error) - { - services.PersistentNotification.Create( - message: error.Message, - title: "Erreur Spotify"); - } - } - ); - } -} diff --git a/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayAlbum/SpotifyplusSearchAlbumsResponse.cs b/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayAlbum/SpotifyplusSearchAlbumsResponse.cs deleted file mode 100644 index b96fe0a5..00000000 --- a/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayAlbum/SpotifyplusSearchAlbumsResponse.cs +++ /dev/null @@ -1,40 +0,0 @@ -namespace Spotify; - -using System.Collections.Generic; - - -public record AlbumItem -{ - public string? AlbumType { get; set; } - public List? Artists { get; set; } - public List? 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? 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 AlbumResult -{ - public string? Href { get; set; } - public int? Limit { get; set; } - public string? Next { get; set; } - public int? Offset { get; set; } - public object? Previous { get; set; } - public int? Total { get; set; } - public List? Items { get; set; } -} - -public record SpotifyplusSearchAlbumsResponse -{ - public UserProfile? UserProfile { get; set; } - public AlbumResult? Result { get; set; } -} diff --git a/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayArtist/PlayArtist.cs b/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayArtist/PlayArtist.cs deleted file mode 100644 index 9cb5764c..00000000 --- a/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayArtist/PlayArtist.cs +++ /dev/null @@ -1,60 +0,0 @@ -namespace Spotify; - -using HomeAssistantGenerated; -using NetDaemon.AppModel; -using NetDaemon.HassModel; -using NetDaemon.HassModel.Integration; -using System; -using System.Text.Json; - -record PlayArtistData(string? artist); - - -[NetDaemonApp] -public class PlayArtist -{ - // Snake-case json options - private readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions - { - PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower - }; - - public PlayArtist(IHaContext ha, Services services, Entities entities) - { - ha.RegisterServiceCallBack( - "spotify_play_artist", - async (e) => - { - try - { - var result = (await services.Spotifyplus.SearchArtistsAsync( - criteria: e?.artist ?? throw new NullReferenceException($"The artist {e?.artist} could not be found."), - limitTotal: 1, - entityId: Global.DEFAULT_ENTITY_ID, - // My Defaults - market: "CA", - includeExternal: "audio" - )).Value.Deserialize(_jsonOptions); - - string uri = result?.Result?.Items?[0]?.Uri ?? - throw new NullReferenceException($"The artist {e?.artist} could not be found."); - - services.Spotifyplus.PlayerMediaPlayContext( - contextUri: uri, - entityId: Global.DEFAULT_ENTITY_ID, - deviceId: Global.DEFAULT_DEV_ID, - // My Defaults - positionMs: 0, - delay: 0.50 - ); - } - catch (Exception error) - { - services.PersistentNotification.Create( - message: error.Message, - title: "Erreur Spotify"); - } - } - ); - } -} diff --git a/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayArtist/SpotifyplusSearchArtistsResponse.cs b/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayArtist/SpotifyplusSearchArtistsResponse.cs deleted file mode 100644 index d4bc12cf..00000000 --- a/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayArtist/SpotifyplusSearchArtistsResponse.cs +++ /dev/null @@ -1,36 +0,0 @@ -namespace Spotify; - -using System.Collections.Generic; - - -public record ArtistItem -{ - public ExternalUrls? External_urls { get; init; } - public Followers? Followers { get; init; } - public List? Genres { get; init; } - public string? Href { get; init; } - public string? Id { get; init; } - public string? Image_url { get; init; } - public List? Images { get; init; } - public string? Name { get; init; } - public int? Popularity { get; init; } - public string? Type { get; init; } - public string? Uri { get; init; } -} - -public record ArtistResult -{ - public string? Href { get; init; } - public int? Limit { get; init; } - public string? Next { get; init; } - public int? Offset { get; set; } - public object? Previous { get; init; } - public int? Total { get; init; } - public List? Items { get; init; } -} - -public record SpotifyplusSearchArtistsResponse -{ - public UserProfile? UserProfile { get; init; } - public ArtistResult? Result { get; init; } -} diff --git a/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayPlaylist/PlayPlaylist.cs b/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayPlaylist/PlayPlaylist.cs deleted file mode 100644 index eb44e3b6..00000000 --- a/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayPlaylist/PlayPlaylist.cs +++ /dev/null @@ -1,89 +0,0 @@ -namespace Spotify; - -using FuzzySharp; -using FuzzySharp.Extractor; -using HomeAssistantGenerated; -using NetDaemon.AppModel; -using NetDaemon.HassModel; -using NetDaemon.HassModel.Integration; -using System; -using System.Collections.Generic; -using System.Text.Json; - -record PlayPlaylistData(string? playlist); - - -[NetDaemonApp] -public class PlayPlaylist -{ - // Snake-case json options - private readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions - { - PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower - }; - - public PlayPlaylist(IHaContext ha, Services services, Entities entities) - { - ha.RegisterServiceCallBack( - "spotify_play_playlist", - async (e) => - { - try - { - string query = e?.playlist ?? throw new NullReferenceException("Query not found."); - - var result = (await services.Spotifyplus.GetPlaylistFavoritesAsync( - limitTotal: 200, - sortResult: true, - entityId: Global.DEFAULT_ENTITY_ID - )).Value.Deserialize(_jsonOptions); - - List myPlaylists = result?.Result?.Items ?? - throw new NullReferenceException($"No playlists found for query {query}"); - - ExtractedResult match = Process.ExtractOne( - new PlaylistsItem { Name = query.ToLower() }, - myPlaylists, - new Func((item) => (item.Name ?? "").ToLower()) - ); - - string uri = match.Value?.Uri ?? - throw new NullReferenceException($"No matches found for query {query}"); - - // We search outside the user's playlists if the score is too low - if (match.Score < 85) - { - var otherResult = (await services.Spotifyplus.SearchPlaylistsAsync( - criteria: query, - limitTotal: 1, - entityId: Global.DEFAULT_ENTITY_ID, - // My Defaults - market: "CA", - includeExternal: "audio" - )).Value.Deserialize(_jsonOptions); - - string potentialUri = otherResult?.Result?.Items?[0]?.Uri ?? - throw new NullReferenceException($"No public matches found for query {query}"); - - uri = potentialUri; - } - - services.Spotifyplus.PlayerMediaPlayContext( - contextUri: uri, - entityId: Global.DEFAULT_ENTITY_ID, - deviceId: Global.DEFAULT_DEV_ID, - // My Defaults - positionMs: 0, - delay: 0.50 - ); - } - catch (Exception error) - { - services.PersistentNotification.Create( - message: error.Message, - title: "Erreur Spotify"); - } - } - ); - } -} diff --git a/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayPlaylist/SpotifyplusPlaylistResponse.cs b/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayPlaylist/SpotifyplusPlaylistResponse.cs deleted file mode 100644 index e433e06c..00000000 --- a/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlayPlaylist/SpotifyplusPlaylistResponse.cs +++ /dev/null @@ -1,39 +0,0 @@ -namespace Spotify; - -using System.Collections.Generic; - - -public record PlaylistsItem -{ - public bool? Collaborative { get; set; } - public string? Description { get; set; } - public ExternalUrls? ExternalUrls { get; set; } - public string? Href { get; set; } - public string? Id { get; set; } - public string? ImageUrl { get; set; } - public List? Images { get; set; } - public string? Name { get; set; } - public Owner? Owner { get; set; } - public bool? Public { get; set; } - public string? SnapshotId { get; set; } - public Tracks? Tracks { get; set; } - public string? Type { get; set; } - public string? Uri { get; set; } -} - -public record PlaylistsResult -{ - 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? Items { get; set; } -} - -public record SpotifyplusPlaylistResponse -{ - public UserProfile? UserProfile { get; set; } - public PlaylistsResult? Result { get; set; } -} diff --git a/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlaySong/PlaySong.cs b/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlaySong/PlaySong.cs deleted file mode 100644 index 0cbe9edb..00000000 --- a/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlaySong/PlaySong.cs +++ /dev/null @@ -1,60 +0,0 @@ -namespace Spotify; - -using HomeAssistantGenerated; -using NetDaemon.AppModel; -using NetDaemon.HassModel; -using NetDaemon.HassModel.Integration; -using System; -using System.Text.Json; - -record PlaySongData(string? artist, string? song); - -[NetDaemonApp] -public class PlaySong -{ - // Snake-case json options - private readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions - { - PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower - }; - - public PlaySong(IHaContext ha, Services services, Entities entities) - { - ha.RegisterServiceCallBack( - "spotify_play_song", - async (e) => - { - try - { - var result = (await services.Spotifyplus.SearchTracksAsync( - criteria: $"{e?.artist} {e?.song}", - limitTotal: 1, - entityId: Global.DEFAULT_ENTITY_ID, - // My Defaults - market: "CA", - includeExternal: "audio" - )).Value.Deserialize(_jsonOptions); - - string uri = result?.Result?.Items?[0]?.Uri ?? throw new NullReferenceException( - $"The song {e?.song}{(e?.artist is null ? "" : $" by {e?.artist}")} could not be found." - ); - - services.Spotifyplus.PlayerMediaPlayTracks( - uris: uri, - entityId: Global.DEFAULT_ENTITY_ID, - deviceId: Global.DEFAULT_DEV_ID, - // My Defaults - positionMs: 0, - delay: 0.50 - ); - } - catch (Exception error) - { - services.PersistentNotification.Create( - message: error.Message, - title: "Erreur Spotify"); - } - } - ); - } -} diff --git a/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlaySong/SpotifyplusSearchTracksResponse.cs b/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlaySong/SpotifyplusSearchTracksResponse.cs deleted file mode 100644 index 64b08b5e..00000000 --- a/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/PlaySong/SpotifyplusSearchTracksResponse.cs +++ /dev/null @@ -1,44 +0,0 @@ -namespace Spotify; - -using System.Collections.Generic; - -public record SongItem -{ - public Album? Album { get; set; } - public List? Artists { get; set; } - public List? AvailableMarkets { get; set; } - public int? DiscNumber { get; set; } - public int? DurationMs { get; set; } - public bool? Explicit { get; set; } - public ExternalIds? ExternalIds { get; set; } - public ExternalUrls? ExternalUrls { get; set; } - public string? Href { get; set; } - public string? Id { get; set; } - public string? ImageUrl { get; set; } - public bool? IsLocal { get; set; } - public object? IsPlayable { get; set; } - public string? Name { get; set; } - public int? Popularity { get; set; } - public object? PreviewUrl { get; set; } - public Restrictions? Restrictions { get; set; } - public int? TrackNumber { get; set; } - public string? Type { get; set; } - public string? Uri { get; set; } -} - -public record SongResult -{ - public string? Href { get; set; } - public int? Limit { get; set; } - public string? Next { get; set; } - public int? Offset { get; set; } - public object? Previous { get; set; } - public int? Total { get; set; } - public List? Items { get; set; } -} - -public record SpotifyplusSearchTracksResponse -{ - public UserProfile? UserProfile { get; set; } - public SongResult? Result { get; set; } -} diff --git a/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/Types.cs b/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/Types.cs deleted file mode 100644 index 6e47a3a3..00000000 --- a/devices/homie/modules/home-assistant/netdaemon/apps/Spotify/Types.cs +++ /dev/null @@ -1,103 +0,0 @@ -namespace Spotify; - -using System.Collections.Generic; - - -public static class Global -{ - public const string DEFAULT_DEV_ID = "homie connect"; - public const string DEFAULT_ENTITY_ID = "media_player.spotifyplus"; -} - - -// https://jsonformatter.org/yaml-to-json -// https://json2csharp.com -// https://github.com/thlucas1/homeassistantcomponent_spotifyplus/blob/master/custom_components/spotifyplus/services.yaml -public record Restrictions { } - -public record UserProfile -{ - public string? Country { get; set; } - public string? DisplayName { get; set; } - public string? Email { get; set; } - public string? Id { get; set; } - public string? Product { get; set; } - public string? Type { get; set; } - public string? Uri { get; set; } -} - -public record ExternalUrls -{ - public string? Spotify { get; set; } -} - -public record Followers -{ - public string? Href { get; set; } - public int? Total { get; set; } -} - -public record Image -{ - public string? Url { get; set; } - public int? Height { get; set; } - public int? Width { get; set; } -} - -public record Owner -{ - public string? DisplayName { get; set; } - public ExternalUrls? ExternalUrls { get; set; } - public Followers? Followers { get; set; } - public string? Href { get; set; } - public string? Id { get; set; } - public string? Type { get; set; } - public string? Uri { get; set; } -} - -public record Tracks -{ - public string? Href { get; set; } - public int? Total { get; set; } -} - -public record Artist -{ - public ExternalUrls? ExternalUrls { get; set; } - public string? Href { get; set; } - public string? Id { get; set; } - public string? Name { get; set; } - public string? Type { get; set; } - public string? Uri { get; set; } -} - -public record ExternalIds -{ - public object? Ean { get; set; } - public string? Isrc { get; set; } - public object? Upc { get; set; } -} - -public record Album -{ - public string? AlbumType { get; set; } - public List? Artists { get; set; } - public List? AvailableMarkets { get; set; } - public List? Copyrights { get; set; } - public ExternalIds? ExternalIds { get; set; } - public ExternalUrls? ExternalUrls { get; set; } - public List? genres { get; set; } - public string? Href { get; set; } - public string? Id { get; set; } - public string? ImageUrl { get; set; } - public List? Images { get; set; } - public object? Label { get; set; } - public string? Name { get; set; } - public object? Popularity { 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; } -} diff --git a/devices/homie/modules/home-assistant/netdaemon/netdaemon.csproj b/devices/homie/modules/home-assistant/netdaemon/netdaemon.csproj index 569c5790..09e4f2a4 100644 --- a/devices/homie/modules/home-assistant/netdaemon/netdaemon.csproj +++ b/devices/homie/modules/home-assistant/netdaemon/netdaemon.csproj @@ -5,8 +5,9 @@ net8.0 12.0 enable - netdaemon + NetDaemonConfig $([System.IO.File]::ReadAllText(".version")) + true diff --git a/devices/homie/modules/home-assistant/netdaemon/program.cs b/devices/homie/modules/home-assistant/netdaemon/program.cs index c6d216e8..8f5c3e2e 100644 --- a/devices/homie/modules/home-assistant/netdaemon/program.cs +++ b/devices/homie/modules/home-assistant/netdaemon/program.cs @@ -1,15 +1,16 @@ +using System; +using System.Reactive.Linq; +using System.Reflection; + using HomeAssistantGenerated; + using Microsoft.Extensions.Hosting; + using NetDaemon.AppModel; using NetDaemon.Extensions.Logging; using NetDaemon.Extensions.Scheduler; using NetDaemon.Extensions.Tts; using NetDaemon.Runtime; -using System; -using System.Reactive.Linq; -using System.Reflection; - -#pragma warning disable CA1812 try { @@ -17,7 +18,7 @@ try .UseNetDaemonDefaultLogging() .UseNetDaemonRuntime() .UseNetDaemonTextToSpeech() - .ConfigureServices((_, services) => + .ConfigureServices(static (_, services) => services .AddAppsFromAssembly(Assembly.GetExecutingAssembly()) .AddNetDaemonStateManager()