diff --git a/docs/configuration/conditions.md b/docs/configuration/conditions.md index 46621fee..cf855bc2 100644 --- a/docs/configuration/conditions.md +++ b/docs/configuration/conditions.md @@ -356,6 +356,7 @@ conditions: | `condition` | Must be `user_agent`. | | `user_agent` | Exactly matches a user-agent, e.g. `Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36` | | `user_agent_re` | Matches a user-agent based on a regular expression, e.g. `Chrome/`. | +| `casting` | If `true` matches if the card is being cast to a Chromecast / TV device, if `false` matches if the card is _NOT_ being cast. | | `companion` | If `true` matches if the user-agent is the Home Assistant companion app, if `false` matches if the user-agent is _NOT_ the Home Assistant companion app. | When multiple parameters are specified they must all match for the condition to @@ -436,6 +437,7 @@ conditions: - condition: user_agent user_agent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" user_agent_re: "Chrome/" + casting: true companion: true - condition: view views: diff --git a/src/conditions/conditions-manager.ts b/src/conditions/conditions-manager.ts index 088ea624..cd6f0a8d 100644 --- a/src/conditions/conditions-manager.ts +++ b/src/conditions/conditions-manager.ts @@ -1,6 +1,7 @@ import { TemplateRenderer } from '../card-controller/templates'; import { getConfigValue } from '../config/management'; import { AdvancedCameraCardCondition } from '../config/schema/conditions/types'; +import { isBeingCasted } from '../utils/casting'; import { isCompanionApp } from '../utils/companion'; import { ConditionsEvaluationResult, @@ -275,6 +276,8 @@ export class ConditionsManager implements ConditionsManagerReadonlyInterface { result: !!newState?.userAgent && (!condition.user_agent || condition.user_agent === newState.userAgent) && + (condition.casting === undefined || + condition.casting === isBeingCasted(newState.userAgent)) && (condition.companion === undefined || condition.companion === isCompanionApp(newState.userAgent)) && (condition.user_agent_re === undefined || diff --git a/src/config/schema/conditions/custom/user-agent.ts b/src/config/schema/conditions/custom/user-agent.ts index 677e2c77..1bce5013 100644 --- a/src/config/schema/conditions/custom/user-agent.ts +++ b/src/config/schema/conditions/custom/user-agent.ts @@ -5,5 +5,6 @@ export const userAgentConditionSchema = z.object({ condition: z.literal('user_agent'), user_agent: z.string().optional(), user_agent_re: regexSchema.optional(), + casting: z.boolean().optional(), companion: z.boolean().optional(), }); diff --git a/src/utils/casting.ts b/src/utils/casting.ts index 9abc4366..cf2a77a9 100644 --- a/src/utils/casting.ts +++ b/src/utils/casting.ts @@ -1,7 +1,6 @@ /** * Determine if the card is currently being casted. - * @returns */ -export const isBeingCasted = (): boolean => { - return !!navigator.userAgent.match(/CrKey\//); +export const isBeingCasted = (userAgent: string = navigator.userAgent): boolean => { + return !!userAgent.match(/CrKey\//); }; diff --git a/tests/conditions/conditions-manager.test.ts b/tests/conditions/conditions-manager.test.ts index 11abc8c8..e35e8c73 100644 --- a/tests/conditions/conditions-manager.test.ts +++ b/tests/conditions/conditions-manager.test.ts @@ -952,6 +952,24 @@ describe('ConditionsManager', () => { expect(manager.getEvaluation().result).toBeFalsy(); }); + it('should match casting', () => { + const stateManager = new ConditionStateManager(); + const manager = new ConditionsManager( + [{ condition: 'user_agent' as const, casting: true }], + stateManager, + ); + + expect(manager.getEvaluation().result).toBeFalsy(); + stateManager.setState({ + userAgent: 'CrKey/1.0', + }); + expect(manager.getEvaluation().result).toBeTruthy(); + stateManager.setState({ + userAgent: userAgent, + }); + expect(manager.getEvaluation().result).toBeFalsy(); + }); + it('should match companion app', () => { const stateManager = new ConditionStateManager(); const manager = new ConditionsManager(