Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 67 additions & 1 deletion src/data/media-player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ import {
mdiPlayPause,
mdiPodcast,
mdiPower,
mdiRepeat,
mdiRepeatOff,
mdiRepeatOnce,
mdiShuffle,
mdiShuffleDisabled,
mdiSkipNext,
mdiSkipPrevious,
mdiStop,
Expand Down Expand Up @@ -49,6 +54,8 @@ interface MediaPlayerEntityAttributes extends HassEntityAttributeBase {
entity_picture_local?: string;
is_volume_muted?: boolean;
volume_level?: number;
repeat?: string;
shuffle?: boolean;
source?: string;
source_list?: string[];
sound_mode?: string;
Expand Down Expand Up @@ -80,7 +87,9 @@ export const SUPPORT_VOLUME_BUTTONS = 1024;
export const SUPPORT_SELECT_SOURCE = 2048;
export const SUPPORT_STOP = 4096;
export const SUPPORT_PLAY = 16384;
export const SUPPORT_REPEAT_SET = 262144;
export const SUPPORT_SELECT_SOUND_MODE = 65536;
export const SUPPORT_SHUFFLE_SET = 32768;
export const SUPPORT_BROWSE_MEDIA = 131072;

export type MediaPlayerBrowseAction = "pick" | "play";
Expand Down Expand Up @@ -233,7 +242,8 @@ export const computeMediaDescription = (
};

export const computeMediaControls = (
stateObj: MediaPlayerEntity
stateObj: MediaPlayerEntity,
useExtendedControls = false
): ControlButton[] | undefined => {
if (!stateObj) {
return undefined;
Expand Down Expand Up @@ -266,6 +276,18 @@ export const computeMediaControls = (
}

const assumedState = stateObj.attributes.assumed_state === true;
const stateAttr = stateObj.attributes;

if (
(state === "playing" || state === "paused" || assumedState) &&
supportsFeature(stateObj, SUPPORT_SHUFFLE_SET) &&
useExtendedControls
) {
buttons.push({
icon: stateAttr.shuffle === true ? mdiShuffle : mdiShuffleDisabled,
action: "shuffle_set",
});
}

if (
(state === "playing" || state === "paused" || assumedState) &&
Expand Down Expand Up @@ -337,6 +359,22 @@ export const computeMediaControls = (
});
}

if (
(state === "playing" || state === "paused" || assumedState) &&
supportsFeature(stateObj, SUPPORT_REPEAT_SET) &&
useExtendedControls
) {
buttons.push({
icon:
stateAttr.repeat === "all"
? mdiRepeat
: stateAttr.repeat === "one"
? mdiRepeatOnce
: mdiRepeatOff,
action: "repeat_set",
});
}

return buttons.length > 0 ? buttons : undefined;
};

Expand Down Expand Up @@ -375,3 +413,31 @@ export const setMediaPlayerVolume = (
volume_level: number
) =>
hass.callService("media_player", "volume_set", { entity_id, volume_level });

export const handleMediaControlClick = (
hass: HomeAssistant,
stateObj: MediaPlayerEntity,
action: string
) =>
hass!.callService(
"media_player",
action,
action === "shuffle_set"
? {
entity_id: stateObj!.entity_id,
shuffle: !stateObj!.attributes.shuffle,
}
: action === "repeat_set"
? {
entity_id: stateObj!.entity_id,
repeat:
stateObj!.attributes.repeat === "all"
? "one"
: stateObj!.attributes.repeat === "off"
? "all"
: "off",
}
: {
entity_id: stateObj!.entity_id,
}
);
14 changes: 7 additions & 7 deletions src/dialogs/more-info/controls/more-info-media_player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { showMediaBrowserDialog } from "../../../components/media-player/show-me
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity";
import {
computeMediaControls,
handleMediaControlClick,
MediaPickedEvent,
MediaPlayerEntity,
SUPPORT_BROWSE_MEDIA,
Expand All @@ -47,7 +48,7 @@ class MoreInfoMediaPlayer extends LitElement {
}

const stateObj = this.stateObj;
const controls = computeMediaControls(stateObj);
const controls = computeMediaControls(stateObj, true);

return html`
<div class="controls">
Expand Down Expand Up @@ -202,6 +203,7 @@ class MoreInfoMediaPlayer extends LitElement {
}

.basic-controls {
display: inline-flex;
flex-grow: 1;
}

Expand Down Expand Up @@ -231,12 +233,10 @@ class MoreInfoMediaPlayer extends LitElement {
}

private _handleClick(e: MouseEvent): void {
this.hass!.callService(
"media_player",
(e.currentTarget! as HTMLElement).getAttribute("action")!,
{
entity_id: this.stateObj!.entity_id,
}
handleMediaControlClick(
this.hass!,
this.stateObj!,
(e.currentTarget as HTMLElement).getAttribute("action")!
);
}

Expand Down
12 changes: 7 additions & 5 deletions src/panels/lovelace/cards/hui-media-control-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
computeMediaControls,
computeMediaDescription,
getCurrentProgress,
handleMediaControlClick,
MediaPickedEvent,
MediaPlayerEntity,
SUPPORT_BROWSE_MEDIA,
Expand Down Expand Up @@ -174,7 +175,7 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
UNAVAILABLE_STATES.includes(entityState) ||
(entityState === "off" && !supportsFeature(stateObj, SUPPORT_TURN_ON));
const hasNoImage = !this._image;
const controls = computeMediaControls(stateObj);
const controls = computeMediaControls(stateObj, false);
const showControls =
controls &&
(!this._veryNarrow ||
Expand Down Expand Up @@ -504,10 +505,11 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
}

private _handleClick(e: MouseEvent): void {
const action = (e.currentTarget! as HTMLElement).getAttribute("action")!;
this.hass!.callService("media_player", action, {
entity_id: this._config!.entity,
});
handleMediaControlClick(
this.hass!,
this._stateObj!,
(e.currentTarget as HTMLElement).getAttribute("action")!
);
}

private _updateProgressBar(): void {
Expand Down
11 changes: 7 additions & 4 deletions src/panels/media-browser/ha-bar-media-player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {
computeMediaDescription,
formatMediaTime,
getCurrentProgress,
handleMediaControlClick,
MediaPlayerEntity,
MediaPlayerItem,
setMediaPlayerVolume,
Expand Down Expand Up @@ -173,7 +174,7 @@ export class BarMediaPlayer extends LitElement {
}

const controls = !this.narrow
? computeMediaControls(stateObj)
? computeMediaControls(stateObj, true)
: (stateObj.state === "playing" &&
(supportsFeature(stateObj, SUPPORT_PAUSE) ||
supportsFeature(stateObj, SUPPORT_STOP))) ||
Expand Down Expand Up @@ -490,9 +491,11 @@ export class BarMediaPlayer extends LitElement {
const action = (e.currentTarget! as HTMLElement).getAttribute("action")!;

if (!this._browserPlayer) {
this.hass!.callService("media_player", action, {
entity_id: this.entityId,
});
handleMediaControlClick(
this.hass!,
this._stateObj!,
(e.currentTarget as HTMLElement).getAttribute("action")!
);
return;
}
if (action === "media_pause") {
Expand Down
2 changes: 2 additions & 0 deletions src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,8 @@
"media_volume_down": "Volume down",
"media_volume_mute": "Volume mute",
"media_volume_unmute": "Volume unmute",
"repeat_set": "Repeat mode",
"shuffle_set": "Shuffle",
"text_to_speak": "Text to speak",
"nothing_playing": "Nothing Playing"
},
Expand Down