From 30253ad472556a5d489bf986bd238a9caa9376a4 Mon Sep 17 00:00:00 2001 From: Johan Frick Date: Sun, 1 Dec 2024 13:19:03 +0100 Subject: [PATCH] feature: make it possible to use a player volume entity outside the group --- README.md | 1 + src/components/player-controls.ts | 34 ++++++++++++++++++++++--------- src/editor/advanced-editor.ts | 4 ++++ src/model/media-player.ts | 4 ++-- src/types.ts | 1 + src/utils/utils.ts | 4 ++++ 6 files changed, 36 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 9d6443d..1e65ecc 100644 --- a/README.md +++ b/README.md @@ -215,6 +215,7 @@ entitiesToIgnoreVolumeLevelFor: # default is empty. Use this if you want to igno artworkMinHeight: 10 # default is 5. Use this to change the minimum height of the artwork in the player section. Unit is in rem. artworkAsBackground: true # default is false. Will show the artwork as background for the player section. playerVolumeEntityId: media_player.bedroom # default is empty. Use this to control the volume of another player in the player section. Entity ID must the selected player or part of the selected player's group, otherwise it will not be controlled. +allowPlayerVolumeEntityOutsideOfGroup: true # default is false. Will allow the playerVolumeEntityId to be outside the group of the selected player. showSourceInPlayer: true # default is false. Will show the source (if available) in the player section. showBrowseMediaInPlayerSection: true # default is false. Will show the browse media button in the player section. showChannelInPlayer: true # default is false. Will show the channel (if available) in the player section. This can for instance be the radio station name. diff --git a/src/components/player-controls.ts b/src/components/player-controls.ts index 3943b0d..4c5452a 100755 --- a/src/components/player-controls.ts +++ b/src/components/player-controls.ts @@ -6,6 +6,7 @@ import { CardConfig, MediaPlayerEntityFeature } from '../types'; import { mdiFastForward, mdiRewind, mdiVolumeMinus, mdiVolumePlus } from '@mdi/js'; import { MediaPlayer } from '../model/media-player'; import { until } from 'lit-html/directives/until.js'; +import { findPlayer } from '../utils/utils'; const { SHUFFLE_SET, REPEAT_SET, PLAY, PAUSE, NEXT_TRACK, PREVIOUS_TRACK, BROWSE_MEDIA } = MediaPlayerEntityFeature; @@ -15,6 +16,7 @@ class PlayerControls extends LitElement { private activePlayer!: MediaPlayer; private mediaControlService!: MediaControlService; private volumePlayer!: MediaPlayer; + private updateMemberVolumes!: boolean; render() { this.config = this.store.config; @@ -22,7 +24,8 @@ class PlayerControls extends LitElement { this.mediaControlService = this.store.mediaControlService; const noUpDown = !!this.config.showVolumeUpAndDownButtons && nothing; const noFastForwardAndRewind = !!this.config.showFastForwardAndRewindButtons && nothing; - this.volumePlayer = this.activePlayer.getMember(this.config.playerVolumeEntityId) ?? this.activePlayer; + this.volumePlayer = this.getVolumePlayer(); + this.updateMemberVolumes = !this.config.playerVolumeEntityId; return html`
@@ -42,26 +45,37 @@ class PlayerControls extends LitElement {
+ .updateMembers=${this.updateMemberVolumes}>
`; } - private volDown = async () => - await this.mediaControlService.volumeDown(this.volumePlayer, !this.config.playerVolumeEntityId); - private volUp = async () => - await this.mediaControlService.volumeUp(this.volumePlayer, !this.config.playerVolumeEntityId); + + private getVolumePlayer() { + let result; + if (this.config.playerVolumeEntityId) { + if (this.config.allowPlayerVolumeEntityOutsideOfGroup) { + result = findPlayer(this.store.allMediaPlayers, this.config.playerVolumeEntityId); + } else { + result = this.activePlayer.getMember(this.config.playerVolumeEntityId); + } + } + return result ?? this.activePlayer; + } + + private volDown = async () => await this.mediaControlService.volumeDown(this.volumePlayer, this.updateMemberVolumes); + private volUp = async () => await this.mediaControlService.volumeUp(this.volumePlayer, this.updateMemberVolumes); private rewind = async () => await this.mediaControlService.seek( - this.volumePlayer, - this.volumePlayer.attributes.media_position - (this.config.fastForwardAndRewindStepSizeSeconds || 15), + this.activePlayer, + this.activePlayer.attributes.media_position - (this.config.fastForwardAndRewindStepSizeSeconds || 15), ); private fastForward = async () => await this.mediaControlService.seek( - this.volumePlayer, - this.volumePlayer.attributes.media_position + (this.config.fastForwardAndRewindStepSizeSeconds || 15), + this.activePlayer, + this.activePlayer.attributes.media_position + (this.config.fastForwardAndRewindStepSizeSeconds || 15), ); private async getAudioInputFormat() { diff --git a/src/editor/advanced-editor.ts b/src/editor/advanced-editor.ts index 1133b03..ffeb095 100644 --- a/src/editor/advanced-editor.ts +++ b/src/editor/advanced-editor.ts @@ -101,6 +101,10 @@ export const ADVANCED_SCHEMA = [ name: 'playerVolumeEntityId', selector: { entity: { multiple: false, filter: { domain: 'media_player' } } }, }, + { + name: 'allowPlayerVolumeEntityOutsideOfGroup', + selector: { boolean: {} }, + }, { name: 'dontSwitchPlayerWhenGrouping', selector: { boolean: {} }, diff --git a/src/model/media-player.ts b/src/model/media-player.ts index 0978755..c4e772a 100644 --- a/src/model/media-player.ts +++ b/src/model/media-player.ts @@ -1,6 +1,6 @@ import { HassEntity } from 'home-assistant-js-websocket'; import { CardConfig } from '../types'; -import { getGroupPlayerIds } from '../utils/utils'; +import { findPlayer, getGroupPlayerIds } from '../utils/utils'; export class MediaPlayer { id: string; @@ -24,7 +24,7 @@ export class MediaPlayer { } getMember(playerId?: string) { - return this.members.find((member) => member.id === playerId); + return findPlayer(this.members, playerId); } hasMember(playerId: string) { diff --git a/src/types.ts b/src/types.ts index ef337f6..8535982 100644 --- a/src/types.ts +++ b/src/types.ts @@ -86,6 +86,7 @@ export interface CardConfig extends LovelaceCardConfig { artworkMinHeight?: number; artworkAsBackground?: boolean; playerVolumeEntityId?: string; + allowPlayerVolumeEntityOutsideOfGroup?: boolean; dontSwitchPlayerWhenGrouping?: boolean; showSourceInPlayer?: boolean; showBrowseMediaInPlayerSection?: boolean; diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 63f4b5d..e2ad9c5 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -142,3 +142,7 @@ export function sortEntities(config: CardConfig, filtered: HassEntity[]) { return filtered.sort((a, b) => a.entity_id.localeCompare(b.entity_id)); } } + +export function findPlayer(mediaPlayers: MediaPlayer[], playerId: string | undefined) { + return mediaPlayers.find((member) => member.id === playerId); +}