Skip to content

Commit 4b92a91

Browse files
committed
[ 1.0.8 ] * Added exception processing for various media controls: seek, volume set, mute.
* Fixed code in the `buildMediaBrowserItems` method that was causing exceptions to be logged for null content.
1 parent c0766b0 commit 4b92a91

File tree

11 files changed

+190
-82
lines changed

11 files changed

+190
-82
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ Change are listed in reverse chronological order (newest to oldest).
66

77
<span class="changelog">
88

9+
###### [ 1.0.8 ] - 2024/10/27
10+
11+
* Added exception processing for various media controls: seek, volume set, mute.
12+
* Fixed code in the `buildMediaBrowserItems` method that was causing exceptions to be logged for null content.
13+
914
###### [ 1.0.7 ] - 2024/10/25
1015

1116
* Added an outline to the player progress bar.

src/card.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ export class Card extends LitElement {
181181
class="spc-card-footer"
182182
.config=${this.config}
183183
.section=${this.section}
184-
@show-section=${this.OnFooterShowSection}
184+
@show-section=${this.onFooterShowSection}
185185
></spc-footer>
186186
</div>`
187187
)}
@@ -402,7 +402,7 @@ export class Card extends LitElement {
402402
if (isCardInEditPreview(this)) {
403403

404404
// add document level event listeners.
405-
document.addEventListener(EDITOR_CONFIG_AREA_SELECTED, this.OnEditorConfigAreaSelectedEventHandler);
405+
document.addEventListener(EDITOR_CONFIG_AREA_SELECTED, this.onEditorConfigAreaSelectedEventHandler);
406406

407407
}
408408

@@ -430,7 +430,7 @@ export class Card extends LitElement {
430430
// return a different value than when the event was added in connectedCallback!
431431

432432
// remove document level event listeners.
433-
document.removeEventListener(EDITOR_CONFIG_AREA_SELECTED, this.OnEditorConfigAreaSelectedEventHandler);
433+
document.removeEventListener(EDITOR_CONFIG_AREA_SELECTED, this.onEditorConfigAreaSelectedEventHandler);
434434

435435
// invoke base class method.
436436
super.disconnectedCallback();
@@ -572,7 +572,7 @@ export class Card extends LitElement {
572572
*
573573
* @param ev Event definition and arguments.
574574
*/
575-
protected OnEditorConfigAreaSelectedEventHandler = (ev: Event) => {
575+
protected onEditorConfigAreaSelectedEventHandler = (ev: Event) => {
576576

577577
// map event arguments.
578578
const evArgs = (ev as CustomEvent).detail as EditorConfigAreaSelectedEventArgs;
@@ -599,7 +599,7 @@ export class Card extends LitElement {
599599
*
600600
* @param args Event arguments that contain the section to show.
601601
*/
602-
protected OnFooterShowSection = (args: CustomEvent) => {
602+
protected onFooterShowSection = (args: CustomEvent) => {
603603

604604
const section = args.detail;
605605
if (!this.config.sections || this.config.sections.indexOf(section) > -1) {

src/components/footer.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,84 +40,84 @@ export class Footer extends LitElement {
4040
<ha-icon-button
4141
.path=${mdiPlayCircle}
4242
label="Player"
43-
@click=${() => this.OnSectionClick(Section.PLAYER)}
43+
@click=${() => this.onSectionClick(Section.PLAYER)}
4444
selected=${this.getSectionSelected(Section.PLAYER)}
4545
hide=${this.getSectionEnabled(Section.PLAYER)}
4646
></ha-icon-button>
4747
<ha-icon-button
4848
.path=${mdiSpeaker}
4949
label="Devices"
50-
@click=${() => this.OnSectionClick(Section.DEVICES)}
50+
@click=${() => this.onSectionClick(Section.DEVICES)}
5151
selected=${this.getSectionSelected(Section.DEVICES)}
5252
hide=${this.getSectionEnabled(Section.DEVICES)}
5353
></ha-icon-button>
5454
<ha-icon-button
5555
.path=${mdiBookmarkMusicOutline}
5656
label="User Presets"
57-
@click=${() => this.OnSectionClick(Section.USERPRESETS)}
57+
@click=${() => this.onSectionClick(Section.USERPRESETS)}
5858
selected=${this.getSectionSelected(Section.USERPRESETS)}
5959
hide=${this.getSectionEnabled(Section.USERPRESETS)}
6060
></ha-icon-button>
6161
<ha-icon-button
6262
.path=${mdiHistory}
6363
label="Recently Played"
64-
@click=${() => this.OnSectionClick(Section.RECENTS)}
64+
@click=${() => this.onSectionClick(Section.RECENTS)}
6565
selected=${this.getSectionSelected(Section.RECENTS)}
6666
hide=${this.getSectionEnabled(Section.RECENTS)}
6767
></ha-icon-button>
6868
<ha-icon-button
6969
.path=${mdiPlaylistPlay}
7070
label='Playlist Favorites'
71-
@click=${() => this.OnSectionClick(Section.PLAYLIST_FAVORITES)}
71+
@click=${() => this.onSectionClick(Section.PLAYLIST_FAVORITES)}
7272
selected=${this.getSectionSelected(Section.PLAYLIST_FAVORITES)}
7373
hide=${this.getSectionEnabled(Section.PLAYLIST_FAVORITES)}
7474
></ha-icon-button>
7575
<ha-icon-button
7676
.path=${mdiAlbum}
7777
label='Album Favorites'
78-
@click=${() => this.OnSectionClick(Section.ALBUM_FAVORITES)}
78+
@click=${() => this.onSectionClick(Section.ALBUM_FAVORITES)}
7979
selected=${this.getSectionSelected(Section.ALBUM_FAVORITES)}
8080
hide=${this.getSectionEnabled(Section.ALBUM_FAVORITES)}
8181
></ha-icon-button>
8282
<ha-icon-button
8383
.path=${mdiAccountMusic}
8484
label='Artist Favorites'
85-
@click=${() => this.OnSectionClick(Section.ARTIST_FAVORITES)}
85+
@click=${() => this.onSectionClick(Section.ARTIST_FAVORITES)}
8686
selected=${this.getSectionSelected(Section.ARTIST_FAVORITES)}
8787
hide=${this.getSectionEnabled(Section.ARTIST_FAVORITES)}
8888
></ha-icon-button>
8989
<ha-icon-button
9090
.path=${mdiMusic}
9191
label='Track Favorites'
92-
@click=${() => this.OnSectionClick(Section.TRACK_FAVORITES)}
92+
@click=${() => this.onSectionClick(Section.TRACK_FAVORITES)}
9393
selected=${this.getSectionSelected(Section.TRACK_FAVORITES)}
9494
hide=${this.getSectionEnabled(Section.TRACK_FAVORITES)}
9595
></ha-icon-button>
9696
<ha-icon-button
9797
.path=${mdiBookOpenVariant}
9898
label='Audiobook Favorites'
99-
@click=${() => this.OnSectionClick(Section.AUDIOBOOK_FAVORITES)}
99+
@click=${() => this.onSectionClick(Section.AUDIOBOOK_FAVORITES)}
100100
selected=${this.getSectionSelected(Section.AUDIOBOOK_FAVORITES)}
101101
hide=${this.getSectionEnabled(Section.AUDIOBOOK_FAVORITES)}
102102
></ha-icon-button>
103103
<ha-icon-button
104104
.path=${mdiPodcast}
105105
label='Show Favorites'
106-
@click=${() => this.OnSectionClick(Section.SHOW_FAVORITES)}
106+
@click=${() => this.onSectionClick(Section.SHOW_FAVORITES)}
107107
selected=${this.getSectionSelected(Section.SHOW_FAVORITES)}
108108
hide=${this.getSectionEnabled(Section.SHOW_FAVORITES)}
109109
></ha-icon-button>
110110
<ha-icon-button
111111
.path=${mdiMicrophone}
112112
label='Episode Favorites'
113-
@click=${() => this.OnSectionClick(Section.EPISODE_FAVORITES)}
113+
@click=${() => this.onSectionClick(Section.EPISODE_FAVORITES)}
114114
selected=${this.getSectionSelected(Section.EPISODE_FAVORITES)}
115115
hide=${this.getSectionEnabled(Section.EPISODE_FAVORITES)}
116116
></ha-icon-button>
117117
<ha-icon-button
118118
.path=${mdiSearchWeb}
119119
label='Search Spotify'
120-
@click=${() => this.OnSectionClick(Section.SEARCH_MEDIA)}
120+
@click=${() => this.onSectionClick(Section.SEARCH_MEDIA)}
121121
selected=${this.getSectionSelected(Section.SEARCH_MEDIA)}
122122
hide=${this.getSectionEnabled(Section.SEARCH_MEDIA)}
123123
></ha-icon-button>
@@ -151,7 +151,7 @@ export class Footer extends LitElement {
151151
*
152152
* @param section Event arguments.
153153
*/
154-
private OnSectionClick(section: Section) {
154+
private onSectionClick(section: Section) {
155155

156156
this.dispatchEvent(customEvent(SHOW_SECTION, section));
157157

src/components/player-controls.ts

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ class PlayerControls extends LitElement {
155155
}
156156

157157
// bound event listeners for event handlers that need access to "this" object.
158-
private OnKeyDown_EventListenerBound;
158+
private onKeyDown_EventListenerBound;
159159

160160
/**
161161
* Initializes a new instance of the class.
@@ -166,7 +166,7 @@ class PlayerControls extends LitElement {
166166
super();
167167

168168
// create bound event listeners for event handlers that need access to "this" object.
169-
this.OnKeyDown_EventListenerBound = this.OnKeyDown.bind(this);
169+
this.onKeyDown_EventListenerBound = this.OnKeyDown.bind(this);
170170
}
171171

172172

@@ -184,7 +184,7 @@ class PlayerControls extends LitElement {
184184
super.connectedCallback();
185185

186186
// add document level event listeners.
187-
document.addEventListener("keydown", this.OnKeyDown_EventListenerBound);
187+
document.addEventListener("keydown", this.onKeyDown_EventListenerBound);
188188

189189
// determine if card configuration is being edited.
190190
this.isCardInEditPreview = isCardInEditPreview(this.store.card);
@@ -205,7 +205,7 @@ class PlayerControls extends LitElement {
205205
public disconnectedCallback() {
206206

207207
// remove document level event listeners.
208-
document.removeEventListener("keydown", this.OnKeyDown_EventListenerBound);
208+
document.removeEventListener("keydown", this.onKeyDown_EventListenerBound);
209209

210210
// invoke base class method.
211211
super.disconnectedCallback();
@@ -309,27 +309,23 @@ class PlayerControls extends LitElement {
309309

310310
await this.mediaControlService.turn_on(this.player);
311311

312-
} else {
313-
314-
// no action selected - hide progress indicator.
315-
this.progressHide();
316-
317312
}
318313

319-
// hide progress indicator.
320-
this.progressHide();
321314
return true;
322315

323316
}
324317
catch (error) {
325318

326-
// clear the progress indicator and set alert error message.
327-
this.progressHide();
319+
// set alert error message.
328320
this.alertErrorSet("Control action failed: \n" + (error as Error).message);
329321
return true;
330322

331323
}
332324
finally {
325+
326+
// hide progress indicator.
327+
this.progressHide();
328+
333329
}
334330

335331
}

src/components/player-progress.ts

Lines changed: 74 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,32 @@ import { styleMap } from 'lit-html/directives/style-map.js';
66
// our imports.
77
import { Store } from '../model/store';
88
import { MediaPlayer } from '../model/media-player';
9+
import { ProgressStartedEvent } from '../events/progress-started';
10+
import { ProgressEndedEvent } from '../events/progress-ended';
11+
import { closestElement } from '../utils/utils';
12+
import { Player } from '../sections/player';
13+
914

1015
class Progress extends LitElement {
1116

12-
/** Application common storage area. */
17+
// public state properties.
1318
@property({ attribute: false }) store!: Store;
1419

20+
// private state properties.
21+
@state() private playingProgress!: number;
22+
1523
/** MediaPlayer instance created from the configuration entity id. */
1624
private player!: MediaPlayer;
1725

18-
/** Current position (in seconds) of the currently playing media. */
19-
@state() private playingProgress!: number;
20-
2126
/** Callback function that calculates the current progress (executed every 1 second). */
2227
private tracker?: NodeJS.Timeout;
2328

24-
/** Progress bar HTMLElement control. */
25-
@query('.bar') private progressBar?: HTMLElement;
26-
2729
/** Current media duration value. */
2830
private mediaDuration = 0;
2931

32+
/** Progress bar HTMLElement control. */
33+
@query('.bar') private progressBar?: HTMLElement;
34+
3035

3136
/**
3237
* Invoked on each update to perform rendering tasks.
@@ -97,13 +102,68 @@ class Progress extends LitElement {
97102
*/
98103
private async onSeekBarClick(args: MouseEvent) {
99104

100-
// calculate the desired position based on the mouse pointer position.
101-
const progressWidth = this.progressBar!.offsetWidth;
102-
const percent = args.offsetX / progressWidth;
103-
const position = this.mediaDuration * percent;
105+
try {
106+
107+
// calculate the desired position based on the mouse pointer position.
108+
const progressWidth = this.progressBar!.offsetWidth;
109+
const percent = args.offsetX / progressWidth;
110+
const position = this.mediaDuration * percent;
111+
112+
// show progress indicator.
113+
this.progressShow();
114+
115+
// call service to seek to track position.
116+
await this.store.mediaControlService.media_seek(this.player, position);
117+
return true;
118+
119+
}
120+
catch (error) {
121+
122+
// set alert error message.
123+
this.alertErrorSet("Seek position failed: \n" + (error as Error).message);
124+
return true;
125+
126+
}
127+
finally {
128+
129+
// hide progress indicator.
130+
this.progressHide();
131+
132+
}
133+
134+
}
135+
136+
137+
/**
138+
* Hide visual progress indicator.
139+
*/
140+
protected progressHide(): void {
141+
this.store.card.dispatchEvent(ProgressEndedEvent());
142+
}
143+
144+
145+
/**
146+
* Show visual progress indicator.
147+
*/
148+
protected progressShow(): void {
149+
this.store.card.dispatchEvent(ProgressStartedEvent());
150+
}
151+
152+
153+
/**
154+
* Sets the alert error message in the parent player.
155+
*
156+
* @param message alert message text.
157+
*/
158+
private alertErrorSet(message: string): void {
159+
160+
// find the parent player reference, and update the message.
161+
// we have to do it this way due to the shadowDOM between this element and the player element.
162+
const spcPlayer = closestElement('#spcPlayer', this) as Player;
163+
if (spcPlayer) {
164+
spcPlayer.alertErrorSet(message);
165+
}
104166

105-
// call service to seek to track position.
106-
await this.store.mediaControlService.media_seek(this.player, position);
107167
}
108168

109169

@@ -181,6 +241,7 @@ class Progress extends LitElement {
181241
margin-right: 2px;
182242
height: 50%;
183243
transition: width 0.1s linear;
244+
border-radius: 0.18rem;
184245
}
185246
186247
.progress-time {

0 commit comments

Comments
 (0)