Skip to content

Commit

Permalink
[ 1.0.4 ] * Added UserPreset section to allow an unlimited number of …
Browse files Browse the repository at this point in the history
…user-defined presets to be selected for playing. Note that these are not SoundTouch device presets, but user-defined presets. They can be added in the card configuration, or a specified as a JSON data file (for sharing among multiple card instances).

  * Added title formatter options support to `playerHeaderNoMediaPlayingText` configuration value.
  * Added customImageUrls keys to support setting player background images: `playerBackground` sets the background image to display for the Player section when the player is powered on; `playerOffBackground` sets the background image to display for the Player section when the player is powered off.
  * Miscellaneous bug fixes.
  • Loading branch information
thlucas1 committed Jun 13, 2024
1 parent 454af4b commit d18cd95
Show file tree
Hide file tree
Showing 47 changed files with 932 additions and 270 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@
/dist/Build.bat
/developer_notes.txt
/New_Release_Instructions.txt
/data/recently_played_cache_9070658C9D4A.xml
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ Change are listed in reverse chronological order (newest to oldest).

<span class="changelog">

###### [ 1.0.4 ] - 2024/06/13

* Added UserPreset section to allow an unlimited number of user-defined presets to be selected for playing. Note that these are not SoundTouch device presets, but user-defined presets. They can be added in the card configuration, or a specified as a JSON data file (for sharing among multiple card instances).
* Added title formatter options support to `playerHeaderNoMediaPlayingText` configuration value.
* Added customImageUrls keys to support setting player background images: `playerBackground` sets the background image to display for the Player section when the player is powered on; `playerOffBackground` sets the background image to display for the Player section when the player is powered off.
* Miscellaneous bug fixes.

###### [ 1.0.3 ] - 2024/05/20

* Updated the Player section to be a basic media player; more features are planned, but I wanted to get something out there that was functional.
Expand Down
31 changes: 22 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,40 @@ Extended support for the Bose SoundTouch line of speaker products for use in Hom

## Features

* Media player interface with customizable controls and information display
* Display / Select / Store SoundTouch Device Presets
* Display / Select User-Defined Presets
* Display / Select SoundTouch Device Recently Played items
* Display / Select your Pandora Stations
* Display / Select Source Inputs
* Card Configuration Editor User-Interface for changing options

with more to come!

## How it Looks

Here's a quick overview on what the card looks like; check out the [UI Dashboards wiki](https://github.com/thlucas1/homeassistantcomponent_soundtouchplus_card/wiki/UI-Dashboards) page for more examples and YAML configuration.
Here's a quick overview on what the card can look like. The card is highly customizable when it comes to the information displayed. Check out the [UI Dashboards wiki](https://github.com/thlucas1/homeassistantcomponent_soundtouchplus_card/wiki/UI-Dashboards) page for more examples and YAML configuration.

_Pandora Stations, Panel Mode_
<img src="images/panel_pandora.png?v01_20240317">
#### Media Player Control (Panel Mode)
![Media Player Control, Panel Mode](images/player_nofooter_panel.png?v01_20240613)

_SoundTouch Presets, Panel Mode_
<img src="images/panel_presets.png?v01_20240512">
#### SoundTouch Recently Played (Panel Mode)
![SoundTouch Recently Played, Panel Mode](images/recentlyplayed_nofooter_panel.png?v01_20240613)

_SoundTouch Recently Played, Panel Mode_
<img src="images/panel_recently_played.png?v01_20240512">
#### User-Defined Presets (Panel Mode)
![SoundTouch Presets, Panel Mode](images/presets_user_nofooter_panel.png?v01_20240613)

_Editor UI, General Options_
<img src="images/general_editor_ui.jpg?v01_20240512">
#### SoundTouch Device Presets (Panel Mode)
![SoundTouch Presets, Panel Mode](images/presets_device_nofooter_panel.png?v01_20240613)

#### SoundTouch Sources (Panel Mode)
![SoundTouch Sources Panel Mode](images/sources_nofooter_panel.png?v01_20240613)

#### Pandora Stations (Panel Mode)
![Pandora Stations Panel Mode](images/pandora_nofooter_panel.png?v01_20240613)

#### Editor UI, General Options
![Editor UI, General Options](images/general_editor_options.png?v01_20240613)

## HACS Installation Instructions (recommended)

Expand Down
6 changes: 2 additions & 4 deletions SoundTouchPlusCard.njsproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,6 @@
<Content Include=".prettierrc.js" />
<Content Include=".vscode\launch.json" />
<Content Include="CHANGELOG.md" />
<Content Include="data\recently_played_cache_9070658C9D4A.xml">
<SubType>Code</SubType>
</Content>
<Content Include="developer_notes.txt">
<SubType>Code</SubType>
</Content>
Expand Down Expand Up @@ -79,7 +76,6 @@
<Folder Include=".vscode\" />
<Folder Include="dist" />
<Folder Include="images\" />
<Folder Include="data\" />
<Folder Include="src" />
<Folder Include="src\components" />
<Folder Include="src\editor" />
Expand All @@ -99,6 +95,7 @@
</TypeScriptCompile>
<TypeScriptCompile Include="src\components\player-progress.ts" />
<TypeScriptCompile Include="src\components\player-volume.ts" />
<TypeScriptCompile Include="src\editor\userpreset-browser-editor.ts" />
<TypeScriptCompile Include="src\editor\source-browser-editor.ts" />
<TypeScriptCompile Include="src\editor\player-volume-editor.ts" />
<TypeScriptCompile Include="src\editor\player-editor.ts" />
Expand All @@ -109,6 +106,7 @@
<TypeScriptCompile Include="src\sections\source-browser.ts" />
<TypeScriptCompile Include="src\sections\pandora-browser.ts" />
<TypeScriptCompile Include="src\sections\recent-browser.ts" />
<TypeScriptCompile Include="src\sections\userpreset-browser.ts" />
<TypeScriptCompile Include="src\services\media-control-service.ts" />
<TypeScriptCompile Include="src\services\soundtouchplus-service.ts" />
<TypeScriptCompile Include="src\types\cardconfig.ts">
Expand Down
33 changes: 0 additions & 33 deletions data/recently_played_cache_9070658C9D4A.xml

This file was deleted.

Binary file added images/general_editor_options.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed images/general_editor_ui.jpg
Binary file not shown.
Binary file added images/pandora_nofooter_panel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed images/panel_pandora.png
Binary file not shown.
Binary file removed images/panel_presets.png
Binary file not shown.
Binary file removed images/panel_recently_played.png
Binary file not shown.
Binary file added images/player_nofooter_panel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/presets_device_nofooter_panel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/presets_user_nofooter_panel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/recentlyplayed_nofooter_panel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/sources_nofooter_panel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.2.3",
"@types/jest": "27.4.1",
"@types/query-selector-shadow-dom": "^1.0.4",
"@typescript-eslint/eslint-plugin": "^7.6.0",
"@typescript-eslint/parser": "^7.7.0",
"eslint": "^8.57.0",
Expand Down
69 changes: 34 additions & 35 deletions src/card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ const {
PLAYER,
PRESETS,
RECENTS,
SOURCES
SOURCES,
USERPRESETS
} = Section;

const HEADER_HEIGHT = 2;
Expand All @@ -33,12 +34,8 @@ const CARD_DEFAULT_WIDTH = '35.15rem';
const CARD_EDIT_PREVIEW_HEIGHT = '42rem';
const CARD_EDIT_PREVIEW_WIDTH = '100%';

//const PARENTELEMENT_TAGNAME_HUI_CARD_OPTIONS = 'HUI-CARD-OPTIONS';
//const PARENTELEMENT_TAGNAME_HUI_CARD_PREVIEW = 'HUI-CARD-PREVIEW';

const EDIT_TAB_HEIGHT = '48px';
const EDIT_BOTTOM_TOOLBAR_HEIGHT = '59px';
//const CARD_EDIT_PREVIEW_WIDTH = 35.3; // width of card editor parent.

// Good source of help documentation on HA custom cards:
// https://gist.github.com/thomasloven/1de8c62d691e754f95b023105fe4b74b
Expand Down Expand Up @@ -126,6 +123,7 @@ export class Card extends LitElement {
[PRESETS, () => html` <stpc-preset-browser .store=${this.store} @item-selected=${this.onMediaListItemSelected}></stp-presets-browser>`],
[RECENTS, () => html` <stpc-recent-browser .store=${this.store} @item-selected=${this.onMediaListItemSelected}></stp-recents-browser>`],
[SOURCES, () => html` <stpc-source-browser .store=${this.store} @item-selected=${this.onMediaListItemSelected}></stp-source-browser>`],
[USERPRESETS, () => html` <stpc-userpreset-browser .store=${this.store} @item-selected=${this.onMediaListItemSelected}></stp-userpresets-browser>`],
])
: html`<div class="stpc-not-configured">Player not configured</div>`
}
Expand Down Expand Up @@ -250,6 +248,18 @@ export class Card extends LitElement {
ha-circular-progress {
--md-sys-color-primary: var(--dark-primary-color);
}
/* TODO TEST - reduce margin between editor controls */
.root > * {
display: block;
margin-bottom: 0px;
border: 1px solid red !important;
}
/* TODO TEST - reduce margin between editor controls */
.root > *:not([own-margin]):not(:last-child) {
margin-bottom: 0px;
border: 1px solid yellow !important;
}
`;
}

Expand Down Expand Up @@ -381,11 +391,9 @@ export class Card extends LitElement {
protected OnSectionSelected = (args: Event) => {

const sectionToSelect = (args as CustomEvent).detail as Section;
//console.log("card.OnSectionSelected() - sectionToSelect:\n%s", sectionToSelect);

// is section activated? if so, then select it.
if (this.config.sections?.includes(sectionToSelect)) {
//setTimeout(() => (this.section = sectionToSelect), 1000);
this.section = sectionToSelect;
}
}
Expand All @@ -401,16 +409,13 @@ export class Card extends LitElement {
*/
protected OnShowSection = (args: CustomEvent) => {

//console.log("OnShowSection\n this.config.sections=%s\n event section=%s\n this.section=%s", JSON.stringify(this.config.sections), JSON.stringify(args.detail), JSON.stringify(this.section));

const section = args.detail;
//console.log("card.OnShowSection()\n this.section=%s", JSON.stringify(section));

if (!this.config.sections || this.config.sections.indexOf(section) > -1) {
this.section = section;
//this.requestUpdate();
} else {
console.log("STPC - card.OnShowSection()\n section is not active: %s", JSON.stringify(section));
//console.log("STPC - card.OnShowSection()\n section is not active: %s", JSON.stringify(section));
}
}

Expand Down Expand Up @@ -475,6 +480,8 @@ export class Card extends LitElement {
}

// default configration values if not set.
newConfig.pandoraBrowserItemsPerRow = newConfig.pandoraBrowserItemsPerRow || 9;
newConfig.pandoraBrowserItemsHideTitle = newConfig.pandoraBrowserItemsHideTitle || false;
newConfig.playerHeaderHide = newConfig.playerHeaderHide || false;
newConfig.playerHeaderHideProgressBar = newConfig.playerHeaderHideProgressBar || false;
newConfig.playerControlsHidePlayPause = newConfig.playerControlsHidePlayPause || false;
Expand All @@ -488,9 +495,10 @@ export class Card extends LitElement {
newConfig.recentBrowserItemsPerRow = newConfig.recentBrowserItemsPerRow || 10;
newConfig.recentBrowserItemsHideSource = newConfig.recentBrowserItemsHideSource || false;
newConfig.recentBrowserItemsHideTitle = newConfig.recentBrowserItemsHideTitle || false;
newConfig.pandoraBrowserItemsPerRow = newConfig.pandoraBrowserItemsPerRow || 9;
newConfig.pandoraBrowserItemsHideTitle = newConfig.pandoraBrowserItemsHideTitle || false;
newConfig.sourceBrowserItemsPerRow = newConfig.sourceBrowserItemsPerRow || 3;
newConfig.userPresetBrowserItemsPerRow = newConfig.userPresetBrowserItemsPerRow || 3;
newConfig.userPresetBrowserItemsHideSource = newConfig.userPresetBrowserItemsHideSource || false;
newConfig.userPresetBrowserItemsHideTitle = newConfig.userPresetBrowserItemsHideTitle || false;

// if custom imageUrl's are supplied, then remove special characters from each title
// to speed up comparison when imageUrl's are loaded later on. we will also
Expand Down Expand Up @@ -568,25 +576,17 @@ export class Card extends LitElement {
*/
public static getStubConfig(): Record<string, unknown> {

// TODO - add code to search for SoundTouch entities that are already installed,
// and default the "entity" key value.

// does entity id exist in hass state data?
//for const player as SoundTouchPlusHassEntity = Object.values(hass.states)
// .filter((ent) => ent.entity_id.match(entityId));

return {
sections: [Section.PRESETS, Section.RECENTS],
entity: "",
title: 'SoundTouch Card "{player.name}"',
playerHeaderTitle: '{player.name}',
playerHeaderTitle: '{player.source_noaccount}',
playerHeaderArtistTrack: '{player.media_artist} - {player.media_title}',
playerHeaderAlbum: '{player.media_album_name}',
playerHeaderNoMediaPlayingText: 'no media is playing',
playerHeaderNoMediaPlayingText: '"{player.name}" state is "{player.state}"',
sourceBrowserTitle: '"{player.name}" Sources ({medialist.itemcount} items)',
sourceBrowserSubTitle: 'click an item to select the source',
sourceBrowserItemsPerRow: 1,
presetBrowserTitle: '"{player.name}" Presets',
presetBrowserTitle: '"{player.name}" Device Presets',
presetBrowserSubTitle: "last updated on {player.soundtouchplus_presets_lastupdated} ({medialist.itemcount} items)",
presetBrowserItemsPerRow: 3,
presetBrowserItemsHideTitle: false,
Expand All @@ -597,9 +597,14 @@ export class Card extends LitElement {
recentBrowserItemsHideTitle: false,
recentBrowserItemsHideSource: false,
pandoraBrowserTitle: '"{player.name}" My Pandora Stations',
pandoraBrowserSubTitle: "refreshed on {lastupdatedon} ({medialist.itemcount} items)",
pandoraBrowserSubTitle: "refreshed on {medialist.lastupdatedon} ({medialist.itemcount} items)",
pandoraBrowserItemsPerRow: 4,
pandoraBrowserItemsHideTitle: false,
userPresetBrowserTitle: 'User Presets',
userPresetBrowserSubTitle: "refreshed on {medialist.lastupdatedon} ({medialist.itemcount} items)",
userPresetBrowserItemsPerRow: 4,
userPresetBrowserItemsHideTitle: false,
userPresetBrowserItemsHideSource: false,
customImageUrls: {
"default": "/local/images/soundtouchplus_card_customimages/default.png",
"empty preset": "/local/images/soundtouchplus_card_customimages/empty_preset.png",
Expand Down Expand Up @@ -651,13 +656,10 @@ export class Card extends LitElement {
// - if number value specified, then use as width (in rem units).
// - if no value specified, then use default.
if (this.config.width == 'fill') {
//console.log("card.styleCard() width - fill specified");
cardWidth = '100%';
} else if (isNumber(this.config.width)) {
//console.log("card.styleCard() width - number was specified");
cardWidth = this.config.width + 'rem';
} else if (isNumber(String(this.config.width))) {
cardWidth = String(this.config.width) + 'rem';
} else {
//console.log("card.styleCard() width - config not specified; use default");
cardWidth = CARD_DEFAULT_WIDTH;
}

Expand All @@ -666,13 +668,10 @@ export class Card extends LitElement {
// - if number value specified, then use as height (in rem units).
// - if no value specified, then use default.
if (this.config.height == 'fill') {
//console.log("card.styleCard() height - fill specified");
cardHeight = 'calc(100vh - var(--stpc-card-footer-height) - var(--stpc-card-edit-tab-height) - var(--stpc-card-edit-bottom-toolbar-height))';
} else if (isNumber(this.config.height)) {
//console.log("card.styleCard() height - number was specified");
cardHeight = this.config.height + 'rem';
} else if (isNumber(String(this.config.height))) {
cardHeight = String(this.config.height) + 'rem';
} else {
//console.log("card.styleCard() height - config not specified; use default");
cardHeight = CARD_DEFAULT_HEIGHT;
}

Expand Down
9 changes: 9 additions & 0 deletions src/components/footer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { css, html, LitElement, TemplateResult, nothing } from 'lit';
import { property } from 'lit/decorators.js';
import {
mdiAudioInputRca,
mdiBookmarkMusicOutline,
mdiHistory,
mdiPandora,
mdiPlayCircle,
Expand All @@ -22,6 +23,7 @@ const {
PRESETS,
RECENTS,
SOURCES,
USERPRESETS,
} = Section;

class Footer extends LitElement {
Expand Down Expand Up @@ -58,6 +60,13 @@ class Footer extends LitElement {
selected=${this.setSection(PRESETS)}
hide=${this.getSectionEnabled(PRESETS)}
></ha-icon-button>
<ha-icon-button
.path=${mdiBookmarkMusicOutline}
.label="Presets"
@click=${() => this.OnSectionClick(USERPRESETS)}
selected=${this.setSection(USERPRESETS)}
hide=${this.getSectionEnabled(USERPRESETS)}
></ha-icon-button>
<ha-icon-button
.path=${mdiHistory}
.label="Recently Played"
Expand Down
Loading

0 comments on commit d18cd95

Please sign in to comment.