Add auto_play and auto_unmute for consistency.
This commit is contained in:
@@ -1,18 +1,25 @@
|
||||
import { EmblaCarouselType, EmblaPluginType } from 'embla-carousel';
|
||||
import { AutoMuteCondition, AutoPauseCondition, FrigateCardMediaPlayer } from '../../types.js';
|
||||
import {
|
||||
AutoMuteCondition,
|
||||
AutoPauseCondition,
|
||||
AutoPlayCondition,
|
||||
AutoUnmuteCondition,
|
||||
FrigateCardMediaPlayer,
|
||||
} from '../../types.js';
|
||||
|
||||
export type AutoMediaPluginOptionsType = {
|
||||
playerSelector: string;
|
||||
autoPlayWhenVisible?: boolean;
|
||||
autoUnmuteWhenVisible?: boolean;
|
||||
|
||||
// Note: Neither play nor unmute will activate on selection. The caller is
|
||||
// expected to call the methods manually when the media is actually loaded
|
||||
// (not just the slide shown).
|
||||
autoPlayCondition?: AutoPlayCondition;
|
||||
autoUnmuteCondition?: AutoUnmuteCondition;
|
||||
autoPauseCondition?: AutoPauseCondition;
|
||||
autoMuteCondition?: AutoMuteCondition;
|
||||
};
|
||||
|
||||
export const defaultOptions: Partial<AutoMediaPluginOptionsType> = {
|
||||
autoPlayWhenVisible: true,
|
||||
autoUnmuteWhenVisible: true,
|
||||
};
|
||||
export const defaultOptions: Partial<AutoMediaPluginOptionsType> = {};
|
||||
|
||||
export type AutoMediaPluginType = EmblaPluginType<AutoMediaPluginOptionsType> & {
|
||||
play: () => void;
|
||||
@@ -102,10 +109,16 @@ export function AutoMediaPlugin(
|
||||
muteAll();
|
||||
}
|
||||
} else if (document.visibilityState == 'visible') {
|
||||
if (options.autoPlayWhenVisible) {
|
||||
if (
|
||||
options.autoPlayCondition &&
|
||||
['all', 'visible'].includes(options.autoPlayCondition)
|
||||
) {
|
||||
play();
|
||||
}
|
||||
if (options.autoUnmuteWhenVisible) {
|
||||
if (
|
||||
options.autoUnmuteCondition &&
|
||||
['all', 'visible'].includes(options.autoUnmuteCondition)
|
||||
) {
|
||||
unmute();
|
||||
}
|
||||
}
|
||||
@@ -174,7 +187,7 @@ export function AutoMediaPlugin(
|
||||
/**
|
||||
* Mute all slides.
|
||||
*/
|
||||
function muteAll(): void {
|
||||
function muteAll(): void {
|
||||
for (const slide of slides) {
|
||||
getPlayer(slide)?.mute();
|
||||
}
|
||||
|
||||
+25
-4
@@ -299,22 +299,42 @@ export class FrigateCardLiveCarousel extends FrigateCardMediaCarousel {
|
||||
}),
|
||||
AutoMediaPlugin({
|
||||
playerSelector: 'frigate-card-live-provider',
|
||||
autoUnmuteWhenVisible: !!this.liveConfig?.auto_unmute,
|
||||
...(this.liveConfig?.auto_play && {
|
||||
autoPlayCondition: this.liveConfig.auto_play,
|
||||
}),
|
||||
...(this.liveConfig?.auto_pause && {
|
||||
autoPauseCondition: this.liveConfig.auto_pause,
|
||||
}),
|
||||
...(this.liveConfig?.auto_mute && {
|
||||
autoMuteCondition: this.liveConfig.auto_mute,
|
||||
}),
|
||||
...(this.liveConfig?.auto_unmute && {
|
||||
autoUnmuteCondition: this.liveConfig.auto_unmute,
|
||||
}),
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmute the media on the selected slide.
|
||||
* Play the media on the loaded slide.
|
||||
*/
|
||||
protected _autoUnmuteHandler(): void {
|
||||
if (this.liveConfig?.auto_unmute) {
|
||||
protected _autoPlayHandler(): void {
|
||||
if (
|
||||
this.liveConfig?.auto_play &&
|
||||
['all', 'selected'].includes(this.liveConfig.auto_play)
|
||||
) {
|
||||
super._autoPlayHandler();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmute the media on the loaded slide.
|
||||
*/
|
||||
protected _autoUnmuteHandler(): void {
|
||||
if (
|
||||
this.liveConfig?.auto_unmute &&
|
||||
['all', 'selected'].includes(this.liveConfig.auto_unmute)
|
||||
) {
|
||||
super._autoUnmuteHandler();
|
||||
}
|
||||
}
|
||||
@@ -984,6 +1004,7 @@ export class FrigateCardLiveJSMPEG extends LitElement {
|
||||
// The media carousel may automatically pause when the browser tab is
|
||||
// inactive, JSMPEG does not need to also do so independently.
|
||||
pauseWhenHidden: false,
|
||||
autoplay: false,
|
||||
protocols: [],
|
||||
audio: false,
|
||||
videoBufferSize: 1024 * 1024 * 4,
|
||||
|
||||
@@ -206,23 +206,32 @@ export class FrigateCardViewerCarousel extends FrigateCardMediaCarousel {
|
||||
}
|
||||
|
||||
/**
|
||||
* Play the media on the selected slide.
|
||||
* Play the media on the loaded slide.
|
||||
*/
|
||||
protected _autoPlayHandler(): void {
|
||||
if (this.viewerConfig?.auto_play) {
|
||||
protected _autoPlayHandler(): void {
|
||||
if (
|
||||
this.viewerConfig?.auto_play &&
|
||||
['all', 'selected'].includes(this.viewerConfig.auto_play)
|
||||
) {
|
||||
super._autoPlayHandler();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmute the media on the selected slide.
|
||||
* Unmute the media on the loaded slide.
|
||||
*/
|
||||
protected _autoUnmuteHandler(): void {
|
||||
if (this.viewerConfig?.auto_unmute) {
|
||||
if (
|
||||
this.viewerConfig?.auto_unmute &&
|
||||
['all', 'selected'].includes(this.viewerConfig.auto_unmute)
|
||||
) {
|
||||
super._autoUnmuteHandler();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the carousel.
|
||||
*/
|
||||
protected _destroyCarousel(): void {
|
||||
super._destroyCarousel();
|
||||
|
||||
@@ -280,14 +289,18 @@ export class FrigateCardViewerCarousel extends FrigateCardMediaCarousel {
|
||||
}),
|
||||
AutoMediaPlugin({
|
||||
playerSelector: 'frigate-card-ha-hls-player',
|
||||
autoPlayWhenVisible: !!this.viewerConfig?.auto_play,
|
||||
autoUnmuteWhenVisible: !!this.viewerConfig?.auto_unmute,
|
||||
...(this.viewerConfig?.auto_play && {
|
||||
autoPlayCondition: this.viewerConfig.auto_play,
|
||||
}),
|
||||
...(this.viewerConfig?.auto_pause && {
|
||||
autoPauseCondition: this.viewerConfig.auto_pause,
|
||||
}),
|
||||
...(this.viewerConfig?.auto_mute && {
|
||||
autoMuteCondition: this.viewerConfig.auto_mute,
|
||||
}),
|
||||
...(this.viewerConfig?.auto_unmute && {
|
||||
autoUnmuteCondition: this.viewerConfig.auto_unmute,
|
||||
}),
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ import {
|
||||
CONF_VIEW_DEFAULT,
|
||||
CONF_VIEW_TIMEOUT_SECONDS,
|
||||
CONF_VIEW_UPDATE_ENTITIES,
|
||||
CONF_LIVE_AUTO_UNMUTE,
|
||||
CONF_EVENT_VIEWER_AUTO_UNMUTE,
|
||||
} from './const';
|
||||
import {
|
||||
BUTTON_SIZE_MIN,
|
||||
@@ -592,4 +594,13 @@ const UPGRADES = [
|
||||
upgrade(CONF_LIVE_LAZY_UNLOAD, (val) =>
|
||||
typeof val === 'boolean' ? (val ? 'all' : 'never') : undefined,
|
||||
),
|
||||
upgrade(CONF_LIVE_AUTO_UNMUTE, (val) =>
|
||||
typeof val === 'boolean' ? (val ? 'all' : 'never') : undefined,
|
||||
),
|
||||
upgrade(CONF_EVENT_VIEWER_AUTO_PLAY, (val) =>
|
||||
typeof val === 'boolean' ? (val ? 'all' : 'never') : undefined,
|
||||
),
|
||||
upgrade(CONF_EVENT_VIEWER_AUTO_UNMUTE, (val) =>
|
||||
typeof val === 'boolean' ? (val ? 'all' : 'never') : undefined,
|
||||
),
|
||||
];
|
||||
|
||||
+2
-1
@@ -43,8 +43,8 @@ export const CONF_EVENT_GALLERY_CONTROLS_THUMBNAILS_SIZE =
|
||||
`${CONF_EVENT_GALLERY}.controls.thumbnails.size` as const;
|
||||
|
||||
export const CONF_EVENT_VIEWER = 'event_viewer' as const;
|
||||
export const CONF_EVENT_VIEWER_AUTO_PAUSE = `${CONF_EVENT_VIEWER}.auto_pause` as const;
|
||||
export const CONF_EVENT_VIEWER_AUTO_PLAY = `${CONF_EVENT_VIEWER}.auto_play` as const;
|
||||
export const CONF_EVENT_VIEWER_AUTO_PAUSE = `${CONF_EVENT_VIEWER}.auto_pause` as const;
|
||||
export const CONF_EVENT_VIEWER_AUTO_MUTE = `${CONF_EVENT_VIEWER}.auto_mute` as const;
|
||||
export const CONF_EVENT_VIEWER_AUTO_UNMUTE = `${CONF_EVENT_VIEWER}.auto_unmute` as const;
|
||||
export const CONF_EVENT_VIEWER_DRAGGABLE = `${CONF_EVENT_VIEWER}.draggable` as const;
|
||||
@@ -69,6 +69,7 @@ export const CONF_EVENT_VIEWER_CONTROLS_TITLE_DURATION_SECONDS =
|
||||
`${CONF_EVENT_VIEWER}.controls.title.duration_seconds` as const;
|
||||
|
||||
export const CONF_LIVE = 'live' as const;
|
||||
export const CONF_LIVE_AUTO_PLAY = `${CONF_LIVE}.auto_play` as const;
|
||||
export const CONF_LIVE_AUTO_PAUSE = `${CONF_LIVE}.auto_pause` as const;
|
||||
export const CONF_LIVE_AUTO_MUTE = `${CONF_LIVE}.auto_mute` as const;
|
||||
export const CONF_LIVE_AUTO_UNMUTE = `${CONF_LIVE}.auto_unmute` as const;
|
||||
|
||||
+33
-11
@@ -54,6 +54,7 @@ import {
|
||||
CONF_IMAGE_URL,
|
||||
CONF_LIVE_AUTO_MUTE,
|
||||
CONF_LIVE_AUTO_PAUSE,
|
||||
CONF_LIVE_AUTO_PLAY,
|
||||
CONF_LIVE_AUTO_UNMUTE,
|
||||
CONF_LIVE_CONTROLS_NEXT_PREVIOUS_SIZE,
|
||||
CONF_LIVE_CONTROLS_NEXT_PREVIOUS_STYLE,
|
||||
@@ -353,7 +354,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
|
||||
{ value: 'auto', label: localize('config.view.dark_modes.auto') },
|
||||
];
|
||||
|
||||
protected _mediaActionConditions: EditorSelectOption[] = [
|
||||
protected _mediaActionNegativeConditions: EditorSelectOption[] = [
|
||||
{ value: '', label: '' },
|
||||
{ value: 'all', label: localize('config.common.media_action_conditions.all') },
|
||||
{
|
||||
@@ -364,6 +365,20 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
|
||||
{ value: 'never', label: localize('config.common.media_action_conditions.never') },
|
||||
];
|
||||
|
||||
protected _mediaActionPositiveConditions: EditorSelectOption[] = [
|
||||
{ value: '', label: '' },
|
||||
{ value: 'all', label: localize('config.common.media_action_conditions.all') },
|
||||
{
|
||||
value: 'selected',
|
||||
label: localize('config.common.media_action_conditions.selected'),
|
||||
},
|
||||
{
|
||||
value: 'visible',
|
||||
label: localize('config.common.media_action_conditions.visible'),
|
||||
},
|
||||
{ value: 'never', label: localize('config.common.media_action_conditions.never') },
|
||||
];
|
||||
|
||||
public setConfig(config: RawFrigateCardConfig): void {
|
||||
// Note: This does not use Zod to parse the configuration, so it may be
|
||||
// partially or completely invalid. It's more useful to have a partially
|
||||
@@ -1006,17 +1021,24 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
|
||||
${this._renderSwitch(CONF_LIVE_LAZY_LOAD, defaults.live.lazy_load)}
|
||||
${this._renderOptionSelector(
|
||||
CONF_LIVE_LAZY_UNLOAD,
|
||||
this._mediaActionConditions,
|
||||
this._mediaActionNegativeConditions,
|
||||
)}
|
||||
${this._renderOptionSelector(
|
||||
CONF_LIVE_AUTO_PLAY,
|
||||
this._mediaActionPositiveConditions,
|
||||
)}
|
||||
${this._renderOptionSelector(
|
||||
CONF_LIVE_AUTO_PAUSE,
|
||||
this._mediaActionConditions,
|
||||
this._mediaActionNegativeConditions,
|
||||
)}
|
||||
${this._renderOptionSelector(
|
||||
CONF_LIVE_AUTO_MUTE,
|
||||
this._mediaActionConditions,
|
||||
this._mediaActionNegativeConditions,
|
||||
)}
|
||||
${this._renderOptionSelector(
|
||||
CONF_LIVE_AUTO_UNMUTE,
|
||||
this._mediaActionPositiveConditions,
|
||||
)}
|
||||
${this._renderSwitch(CONF_LIVE_AUTO_UNMUTE, defaults.live.auto_unmute)}
|
||||
${this._renderOptionSelector(
|
||||
CONF_LIVE_CONTROLS_NEXT_PREVIOUS_STYLE,
|
||||
this._liveNextPreviousControlStyles,
|
||||
@@ -1079,21 +1101,21 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
|
||||
${this._renderOptionSetHeader('event_viewer')}
|
||||
${this._expandedMenus[MENU_OPTIONS] === 'event_viewer'
|
||||
? html` <div class="values">
|
||||
${this._renderSwitch(
|
||||
${this._renderOptionSelector(
|
||||
CONF_EVENT_VIEWER_AUTO_PLAY,
|
||||
defaults.event_viewer.auto_play,
|
||||
this._mediaActionPositiveConditions,
|
||||
)}
|
||||
${this._renderOptionSelector(
|
||||
CONF_EVENT_VIEWER_AUTO_PAUSE,
|
||||
this._mediaActionConditions,
|
||||
this._mediaActionNegativeConditions,
|
||||
)}
|
||||
${this._renderOptionSelector(
|
||||
CONF_EVENT_VIEWER_AUTO_MUTE,
|
||||
this._mediaActionConditions,
|
||||
this._mediaActionNegativeConditions,
|
||||
)}
|
||||
${this._renderSwitch(
|
||||
${this._renderOptionSelector(
|
||||
CONF_EVENT_VIEWER_AUTO_UNMUTE,
|
||||
defaults.event_viewer.auto_unmute,
|
||||
this._mediaActionPositiveConditions,
|
||||
)}
|
||||
${this._renderSwitch(
|
||||
CONF_EVENT_VIEWER_DRAGGABLE,
|
||||
|
||||
@@ -37,7 +37,9 @@
|
||||
"media_action_conditions": {
|
||||
"all": "All opportunities",
|
||||
"unselected": "On unselection",
|
||||
"selected": "On selection",
|
||||
"hidden": "On browser/tab hiding",
|
||||
"visible": "On browser/tab visibility",
|
||||
"never": "Never"
|
||||
}
|
||||
},
|
||||
@@ -127,6 +129,7 @@
|
||||
"draggable": "Live cameras view can be dragged/swiped",
|
||||
"lazy_load": "Live cameras are lazily loaded",
|
||||
"lazy_unload": "Live cameras are lazily unloaded",
|
||||
"auto_play": "Automatically play live cameras",
|
||||
"auto_pause": "Automatically pause live cameras",
|
||||
"auto_mute": "Automatically mute live cameras",
|
||||
"auto_unmute": "Automatically unmute live cameras",
|
||||
|
||||
+50
-16
@@ -64,10 +64,24 @@ export const FRIGATE_MENU_PRIORITY_MAX = 100;
|
||||
const LIVE_PROVIDERS = ['auto', 'ha', 'frigate-jsmpeg', 'webrtc-card'] as const;
|
||||
export type LiveProvider = typeof LIVE_PROVIDERS[number];
|
||||
|
||||
const MEDIA_ACTION_CONDITIONS = ['all', 'unselected', 'hidden', 'never'] as const;
|
||||
export type LazyUnloadCondition = typeof MEDIA_ACTION_CONDITIONS[number];
|
||||
export type AutoMuteCondition = typeof MEDIA_ACTION_CONDITIONS[number];
|
||||
export type AutoPauseCondition = typeof MEDIA_ACTION_CONDITIONS[number];
|
||||
const MEDIA_ACTION_NEGATIVE_CONDITIONS = [
|
||||
'all',
|
||||
'unselected',
|
||||
'hidden',
|
||||
'never',
|
||||
] as const;
|
||||
export type LazyUnloadCondition = typeof MEDIA_ACTION_NEGATIVE_CONDITIONS[number];
|
||||
export type AutoMuteCondition = typeof MEDIA_ACTION_NEGATIVE_CONDITIONS[number];
|
||||
export type AutoPauseCondition = typeof MEDIA_ACTION_NEGATIVE_CONDITIONS[number];
|
||||
|
||||
const MEDIA_ACTION_POSITIVE_CONDITIONS = [
|
||||
'all',
|
||||
'selected',
|
||||
'visible',
|
||||
'never',
|
||||
] as const;
|
||||
export type AutoUnmuteCondition = typeof MEDIA_ACTION_POSITIVE_CONDITIONS[number];
|
||||
export type AutoPlayCondition = typeof MEDIA_ACTION_POSITIVE_CONDITIONS[number];
|
||||
|
||||
export class FrigateCardError extends Error {}
|
||||
|
||||
@@ -562,9 +576,10 @@ export type TitleControlConfig = z.infer<typeof titleControlConfigSchema>;
|
||||
* Live view configuration section.
|
||||
*/
|
||||
const liveConfigDefault = {
|
||||
auto_pause: 'all' as const,
|
||||
auto_play: 'all' as const,
|
||||
auto_pause: 'never' as const,
|
||||
auto_mute: 'all' as const,
|
||||
auto_unmute: false,
|
||||
auto_unmute: 'never' as const,
|
||||
preload: false,
|
||||
lazy_load: true,
|
||||
lazy_unload: 'never' as const,
|
||||
@@ -669,12 +684,23 @@ const liveOverridableConfigSchema = z
|
||||
const liveConfigSchema = liveOverridableConfigSchema
|
||||
.extend({
|
||||
// Non-overrideable parameters.
|
||||
auto_pause: z.enum(MEDIA_ACTION_CONDITIONS).default(liveConfigDefault.auto_pause),
|
||||
auto_mute: z.enum(MEDIA_ACTION_CONDITIONS).default(liveConfigDefault.auto_mute),
|
||||
auto_unmute: z.boolean().default(liveConfigDefault.auto_unmute),
|
||||
auto_play: z
|
||||
.enum(MEDIA_ACTION_POSITIVE_CONDITIONS)
|
||||
.default(liveConfigDefault.auto_play),
|
||||
auto_pause: z
|
||||
.enum(MEDIA_ACTION_NEGATIVE_CONDITIONS)
|
||||
.default(liveConfigDefault.auto_pause),
|
||||
auto_mute: z
|
||||
.enum(MEDIA_ACTION_NEGATIVE_CONDITIONS)
|
||||
.default(liveConfigDefault.auto_mute),
|
||||
auto_unmute: z
|
||||
.enum(MEDIA_ACTION_POSITIVE_CONDITIONS)
|
||||
.default(liveConfigDefault.auto_unmute),
|
||||
preload: z.boolean().default(liveConfigDefault.preload),
|
||||
lazy_load: z.boolean().default(liveConfigDefault.lazy_load),
|
||||
lazy_unload: z.enum(MEDIA_ACTION_CONDITIONS).default(liveConfigDefault.lazy_unload),
|
||||
lazy_unload: z
|
||||
.enum(MEDIA_ACTION_NEGATIVE_CONDITIONS)
|
||||
.default(liveConfigDefault.lazy_unload),
|
||||
draggable: z.boolean().default(liveConfigDefault.draggable),
|
||||
transition_effect: transitionEffectConfigSchema.default(
|
||||
liveConfigDefault.transition_effect,
|
||||
@@ -756,10 +782,10 @@ export type MenuConfig = z.infer<typeof menuConfigSchema>;
|
||||
* Event viewer configuration section (clip, snapshot).
|
||||
*/
|
||||
const viewerConfigDefault = {
|
||||
auto_play: 'all' as const,
|
||||
auto_pause: 'all' as const,
|
||||
auto_play: true,
|
||||
auto_mute: 'all' as const,
|
||||
auto_unmute: false,
|
||||
auto_unmute: 'never' as const,
|
||||
lazy_load: true,
|
||||
draggable: true,
|
||||
transition_effect: 'slide' as const,
|
||||
@@ -794,10 +820,18 @@ export type ViewerNextPreviousControlConfig = z.infer<
|
||||
|
||||
const viewerConfigSchema = z
|
||||
.object({
|
||||
auto_pause: z.enum(MEDIA_ACTION_CONDITIONS).default(viewerConfigDefault.auto_pause),
|
||||
auto_play: z.boolean().default(viewerConfigDefault.auto_play),
|
||||
auto_mute: z.enum(MEDIA_ACTION_CONDITIONS).default(viewerConfigDefault.auto_mute),
|
||||
auto_unmute: z.boolean().default(viewerConfigDefault.auto_unmute),
|
||||
auto_play: z
|
||||
.enum(MEDIA_ACTION_POSITIVE_CONDITIONS)
|
||||
.default(viewerConfigDefault.auto_play),
|
||||
auto_pause: z
|
||||
.enum(MEDIA_ACTION_NEGATIVE_CONDITIONS)
|
||||
.default(viewerConfigDefault.auto_pause),
|
||||
auto_mute: z
|
||||
.enum(MEDIA_ACTION_NEGATIVE_CONDITIONS)
|
||||
.default(viewerConfigDefault.auto_mute),
|
||||
auto_unmute: z
|
||||
.enum(MEDIA_ACTION_POSITIVE_CONDITIONS)
|
||||
.default(viewerConfigDefault.auto_unmute),
|
||||
lazy_load: z.boolean().default(viewerConfigDefault.lazy_load),
|
||||
draggable: z.boolean().default(viewerConfigDefault.draggable),
|
||||
transition_effect: transitionEffectConfigSchema.default(
|
||||
|
||||
Reference in New Issue
Block a user