Skip to content

Instantly share code, notes, and snippets.

@lymbada
Last active May 22, 2022 10:56
Show Gist options
  • Save lymbada/47c9164f14fe1d58ac5b929da6358e17 to your computer and use it in GitHub Desktop.
Save lymbada/47c9164f14fe1d58ac5b929da6358e17 to your computer and use it in GitHub Desktop.
Spotify Select Player - a blueprint that will select a spotify account from an (ordered) list, to play music on a specific player (if available)
# Copyright (c) 2022, Matthew Tilney
# All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
blueprint:
name: Spotify Select Player
description: >
Allows for automatic selection of a spotify account to be used with the specified source:
a) selects the current Spotify account already playing on the source,
b) select an account currently not playing from the (ordered) Spotify Accounts list
Once (if) a sutiable play is found, the source will be set on the specific Spotify account, and the URL linked to the input_text field will start playing;
(to get the Spotify url for media contect, find a Spotify playlist you like, use the ... -> Share -> copy link to playlist; and past this into your specified input_text
Dependencies: HA Spotify Intergration for at least 1 account (but mutiple supported, this is the whole point)
Issues: Sources are only avaliable in Home Assistant (viat the Spotify Intergration & Web-API) if:
1. The account is signed into the specific Spotify account on the source
2. A local App is currently open (and internet accessable) on a device on the same network as the source.
- Workaround on RiPi devices (yet to be posted - May2022), run mutiple raspotify docker containers on the same devices, with the same name, each signed in to a different account
domain: script
input:
source_name:
name: Source Name
description: Name of the source (must be avaliable in the source_list for each spotify player to work on that account)
selector:
text:
media_list:
name: Spotify Accounts
description: Spotify Accounts list (ordere list, 1st one is checked first) for Spotify which could use for playing music
default: {entity_id: []}
selector:
target:
entity:
integration: spotify
media_content:
name: Media Content as Input Text
description: The media content url for spotify, can be playlist album, or track fron a previously populated input_text helper
selector:
entity:
domain: input_text
test_mode_enabled:
name: Test Mode
description: Some actions (specificall the source select and play media) are skipped, and output of which entity would be used is written to the log (WARN level)
default: false
selector:
boolean:
variables:
spotify_accounts: !input 'media_list'
output_source: !input 'source_name'
media_content: !input 'media_content'
test_mode: !input 'test_mode_enabled'
alias: Spotify Select Player (blueprint)
sequence:
- service: homeassistant.update_entity
data: {}
target:
entity_id: >
{% if spotify_accounts is not defined %}{% set spotify_accounts = namespace(entity_id = integration_entities("spotify") ) %}{% endif %} {% set
output_source = 'spotify-player'%} {%- set spotifies = namespace(entities=[])
-%} {% for entity in states.media_player %}
{% if entity.entity_id in spotify_accounts.entity_id %}
{%- set spotifies.entities = spotifies.entities + [entity] -%}
{% set entities = spotifies.entities %}
{% endif %}
{% endfor %} {{ spotifies.entities | map(attribute='entity_id') | list
}}
- delay:
hours: 0
minutes: 0
seconds: 1
milliseconds: 0
- if:
- condition: not
conditions:
- condition: template
value_template: !input 'test_mode_enabled'
then:
- service: media_player.select_source
target:
entity_id: >
{# Determin which media play can be used for the current sctip#} {#
Convert input entity_id list into full spotify entites in the HA
setup #} {% set spotifies = namespace(entities=[]) -%} {% set
potential_players = namespace(entities=[])%} {% set spotify_list =
[] -%} {% for player in spotify_accounts.entity_id %} {% if player
in integration_entities("spotify")%} {# I don't like having to use a
2nd loop, when a way of getting full entity from entity_id as a
command is possiable, this bit will no longer be rquired #} {% for
player_entity in states.media_player %}{% if player_entity.entity_id
== player %} {% set spotifies.entities = spotifies.entities +
[player_entity] -%} {% set entities = spotifies.entities %} {%
endif %}{% endfor %}{% endif %}{% endfor %} {# Perform the specific
selections, 1st if the device is already playing on the source, 2nd
and spotify account not playing that also has acccess to the source
#} {% for player in (spotifies.entities |
selectattr('state','ne','idle') | selectattr('attributes.source',
'search', output_source) | list )%} {%- set
potential_players.entities = potential_players.entities + [player]
-%} {% endfor %} {% for player in (spotifies.entities |
selectattr('state','ne','playing') |
selectattr('attributes.source_list','search',output_source) | list
)%} {%- set potential_players.entities = potential_players.entities
+ [player] -%} {% endfor %} {# Return the 1st spotify entity_id from
the found list#} {{ (potential_players.entities |
map(attribute='entity_id') | list)[0] }}
data:
source: !input 'source_name'
- delay:
hours: 0
minutes: 0
seconds: 2
milliseconds: 500
- service: media_player.play_media
data:
media_content_id: >
{{ states(media_content) }}
media_content_type: playlist
target:
entity_id: >
{# Determin which media play can be used for the current sctip#} {#
Convert input entity_id list into full spotify entites in the HA
setup #} {% set spotifies = namespace(entities=[]) -%} {% set
potential_players = namespace(entities=[])%} {% set spotify_list =
[] -%} {% for player in spotify_accounts.entity_id %} {% if player
in integration_entities("spotify")%} {# I don't like having to use a
2nd loop, when a way of getting full entity from entity_id as a
command is possiable, this bit will no longer be rquired #} {% for
player_entity in states.media_player %}{% if player_entity.entity_id
== player %} {% set spotifies.entities = spotifies.entities +
[player_entity] -%} {% set entities = spotifies.entities %} {%
endif %}{% endfor %}{% endif %}{% endfor %} {# Perform the specific
selections, 1st if the device is already playing on the source, 2nd
and spotify account not playing that also has acccess to the source
#} {% for player in (spotifies.entities |
selectattr('state','ne','idle') | selectattr('attributes.source',
'search', output_source) | list )%} {%- set
potential_players.entities = potential_players.entities + [player]
-%} {% endfor %} {% for player in (spotifies.entities |
selectattr('state','ne','playing') |
selectattr('attributes.source_list','search',output_source) | list
)%} {%- set potential_players.entities = potential_players.entities
+ [player] -%} {% endfor %} {# Return the 1st spotify entity_id from
the found list#} {{ (potential_players.entities |
map(attribute='entity_id') | list)[0] }}
else:
- service: system_log.write
data:
level: warning
message: >
{# Determin which media play can be used for the current sctip#} {#
Convert input entity_id list into full spotify entites in the HA
setup #} {% set spotifies = namespace(entities=[]) -%} {% set
potential_players = namespace(entities=[])%} {% set spotify_list =
[] -%} {% for player in spotify_accounts.entity_id %} {% if player
in integration_entities("spotify")%} {# I don't like having to use a
2nd loop, when a way of getting full entity from entity_id as a
command is possiable, this bit will no longer be rquired #} {% for
player_entity in states.media_player %}{% if player_entity.entity_id
== player %} {% set spotifies.entities = spotifies.entities +
[player_entity] -%} {% set entities = spotifies.entities %} {%
endif %}{% endfor %}{% endif %}{% endfor %} {# Perform the specific
selections, 1st if the device is already playing on the source, 2nd
and spotify account not playing that also has acccess to the source
#} {% for player in (spotifies.entities |
selectattr('state','ne','idle') | selectattr('attributes.source',
'search', output_source) | list )%} {%- set
potential_players.entities = potential_players.entities + [player]
-%} {% endfor %} {% for player in (spotifies.entities |
selectattr('state','ne','playing') |
selectattr('attributes.source_list','search',output_source) | list
)%} {%- set potential_players.entities = potential_players.entities
+ [player] -%} {% endfor %} {# Write out to log file (for enabled
mode) #} List of spotify accounts (1st will be selected)
{{potential_players.entities | map(attribute='entity_id') | list }};
with the source set as: {{ output_source }}; the content will be {{states(media_content)}}- Testmode: {{ test_mode }}
logger: scripts.log
mode: single
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment