fix: media_stop not supported on Google Cast devices (#1605)
* fix: `media_stop` not supported on Google Cast devices * Add tests for new stop functionality --------- Co-authored-by: Dermot Duffy <dermot.duffy@gmail.com>
This commit is contained in:
co-authored by
Dermot Duffy
parent
9098eb3483
commit
1f5d4bd8b0
@@ -1,5 +1,9 @@
|
|||||||
import { CameraConfig, FrigateCardConfig } from '../config/types';
|
import { CameraConfig, FrigateCardConfig } from '../config/types';
|
||||||
import { MEDIA_PLAYER_SUPPORT_BROWSE_MEDIA } from '../const';
|
import {
|
||||||
|
MEDIA_PLAYER_SUPPORT_BROWSE_MEDIA,
|
||||||
|
MEDIA_PLAYER_SUPPORT_STOP,
|
||||||
|
MEDIA_PLAYER_SUPPORT_TURN_OFF,
|
||||||
|
} from '../const';
|
||||||
import { localize } from '../localize/localize';
|
import { localize } from '../localize/localize';
|
||||||
import { errorToConsole } from '../utils/basic';
|
import { errorToConsole } from '../utils/basic';
|
||||||
import { Entity } from '../utils/ha/registry/entity/types';
|
import { Entity } from '../utils/ha/registry/entity/types';
|
||||||
@@ -85,12 +89,26 @@ export class MediaPlayerManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async stop(mediaPlayer: string): Promise<void> {
|
public async stop(mediaPlayer: string): Promise<void> {
|
||||||
await this._api
|
const hass = this._api.getHASSManager().getHASS();
|
||||||
.getHASSManager()
|
const stateObj = hass?.states[mediaPlayer];
|
||||||
.getHASS()
|
if (!stateObj) {
|
||||||
?.callService('media_player', 'media_stop', {
|
return;
|
||||||
entity_id: mediaPlayer,
|
}
|
||||||
});
|
|
||||||
|
let service: string;
|
||||||
|
if (supportsFeature(stateObj, MEDIA_PLAYER_SUPPORT_STOP)) {
|
||||||
|
service = 'media_stop';
|
||||||
|
} else if (supportsFeature(stateObj, MEDIA_PLAYER_SUPPORT_TURN_OFF)) {
|
||||||
|
// Google Cast devices don't support media_stop, but turning off has the
|
||||||
|
// same effect.
|
||||||
|
service = 'turn_off';
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await hass.callService('media_player', service, {
|
||||||
|
entity_id: mediaPlayer,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async playLive(mediaPlayer: string, cameraID: string): Promise<void> {
|
public async playLive(mediaPlayer: string, cameraID: string): Promise<void> {
|
||||||
|
|||||||
+3
-1
@@ -363,7 +363,9 @@ export const CONF_PERFORMANCE_STYLE_BORDER_RADIUS = `${CONF_PERFORMANCE}.style.b
|
|||||||
|
|
||||||
export const CONF_PROFILES = 'profiles' as const;
|
export const CONF_PROFILES = 'profiles' as const;
|
||||||
|
|
||||||
// Taken from https://github.dev/home-assistant/frontend/blob/b5861869e39290fd2e15737e89571dfc543b3ad3/src/data/media-player.ts#L93
|
// Taken from https://github.com/home-assistant/frontend/blob/a759767d794f02527d127802831e68d3caf0cb7a/src/data/media-player.ts#L82
|
||||||
|
export const MEDIA_PLAYER_SUPPORT_TURN_OFF = 256;
|
||||||
|
export const MEDIA_PLAYER_SUPPORT_STOP = 4096;
|
||||||
export const MEDIA_PLAYER_SUPPORT_BROWSE_MEDIA = 131072;
|
export const MEDIA_PLAYER_SUPPORT_BROWSE_MEDIA = 131072;
|
||||||
|
|
||||||
// The number of media items to fetch at a time (for clips/snapshot views, and
|
// The number of media items to fetch at a time (for clips/snapshot views, and
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||||
import { mock } from 'vitest-mock-extended';
|
import { mock } from 'vitest-mock-extended';
|
||||||
import { MediaPlayerManager } from '../../src/card-controller/media-player-manager';
|
import { MediaPlayerManager } from '../../src/card-controller/media-player-manager';
|
||||||
import { MEDIA_PLAYER_SUPPORT_BROWSE_MEDIA } from '../../src/const';
|
import {
|
||||||
|
MEDIA_PLAYER_SUPPORT_BROWSE_MEDIA,
|
||||||
|
MEDIA_PLAYER_SUPPORT_STOP,
|
||||||
|
MEDIA_PLAYER_SUPPORT_TURN_OFF,
|
||||||
|
} from '../../src/const';
|
||||||
import { ExtendedHomeAssistant } from '../../src/types';
|
import { ExtendedHomeAssistant } from '../../src/types';
|
||||||
import { EntityRegistryManager } from '../../src/utils/ha/registry/entity';
|
import { EntityRegistryManager } from '../../src/utils/ha/registry/entity';
|
||||||
import {
|
import {
|
||||||
@@ -179,21 +183,84 @@ describe('MediaPlayerManager', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should stop', async () => {
|
describe('should stop', () => {
|
||||||
const api = createCardAPI();
|
it('should call media_stop when device supports it', async () => {
|
||||||
vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS());
|
const api = createCardAPI();
|
||||||
|
vi.mocked(api.getHASSManager().getHASS).mockReturnValue(
|
||||||
|
createHASS({
|
||||||
|
'media_player.foo': createStateEntity({
|
||||||
|
entity_id: 'media_player.foo',
|
||||||
|
attributes: {
|
||||||
|
supported_features: MEDIA_PLAYER_SUPPORT_STOP,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
const manager = new MediaPlayerManager(api);
|
const manager = new MediaPlayerManager(api);
|
||||||
|
|
||||||
await manager.stop('media_player.foo');
|
await manager.stop('media_player.foo');
|
||||||
|
|
||||||
expect(api.getHASSManager().getHASS()?.callService).toBeCalledWith(
|
expect(api.getHASSManager().getHASS()?.callService).toBeCalledWith(
|
||||||
'media_player',
|
'media_player',
|
||||||
'media_stop',
|
'media_stop',
|
||||||
{
|
{
|
||||||
entity_id: 'media_player.foo',
|
entity_id: 'media_player.foo',
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call turn_off when device does supports it', async () => {
|
||||||
|
const api = createCardAPI();
|
||||||
|
vi.mocked(api.getHASSManager().getHASS).mockReturnValue(
|
||||||
|
createHASS({
|
||||||
|
'media_player.foo': createStateEntity({
|
||||||
|
entity_id: 'media_player.foo',
|
||||||
|
attributes: {
|
||||||
|
supported_features: MEDIA_PLAYER_SUPPORT_TURN_OFF,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const manager = new MediaPlayerManager(api);
|
||||||
|
|
||||||
|
await manager.stop('media_player.foo');
|
||||||
|
|
||||||
|
expect(api.getHASSManager().getHASS()?.callService).toBeCalledWith(
|
||||||
|
'media_player',
|
||||||
|
'turn_off',
|
||||||
|
{
|
||||||
|
entity_id: 'media_player.foo',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should do nothing without some supported feature', async () => {
|
||||||
|
const api = createCardAPI();
|
||||||
|
vi.mocked(api.getHASSManager().getHASS).mockReturnValue(
|
||||||
|
createHASS({
|
||||||
|
'media_player.foo': createStateEntity({
|
||||||
|
entity_id: 'media_player.foo',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
const manager = new MediaPlayerManager(api);
|
||||||
|
|
||||||
|
await manager.stop('media_player.foo');
|
||||||
|
|
||||||
|
expect(api.getHASSManager().getHASS()?.callService).not.toBeCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should do nothing without hass state', async () => {
|
||||||
|
const api = createCardAPI();
|
||||||
|
vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS());
|
||||||
|
const manager = new MediaPlayerManager(api);
|
||||||
|
|
||||||
|
await manager.stop('media_player.foo');
|
||||||
|
|
||||||
|
expect(api.getHASSManager().getHASS()?.callService).not.toBeCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('should play', () => {
|
describe('should play', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user