Initial attempt at auto_pause .
This commit is contained in:
@@ -1,10 +1,11 @@
|
|||||||
import { EmblaCarouselType, EmblaPluginType } from 'embla-carousel';
|
import { EmblaCarouselType, EmblaPluginType } from 'embla-carousel';
|
||||||
import { FrigateCardMediaPlayer } from '../../types.js';
|
import { AutoPauseCondition, FrigateCardMediaPlayer } from '../../types.js';
|
||||||
|
|
||||||
export type AutoMediaPluginOptionsType = {
|
export type AutoMediaPluginOptionsType = {
|
||||||
playerSelector: string;
|
playerSelector: string;
|
||||||
autoPlayWhenVisible?: boolean;
|
autoPlayWhenVisible?: boolean;
|
||||||
autoUnmuteWhenVisible?: boolean;
|
autoUnmuteWhenVisible?: boolean;
|
||||||
|
autoPauseCondition?: AutoPauseCondition;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const defaultOptions: Partial<AutoMediaPluginOptionsType> = {
|
export const defaultOptions: Partial<AutoMediaPluginOptionsType> = {
|
||||||
@@ -17,12 +18,12 @@ export type AutoMediaPluginType = EmblaPluginType<AutoMediaPluginOptionsType> &
|
|||||||
pause: () => void;
|
pause: () => void;
|
||||||
mute: () => void;
|
mute: () => void;
|
||||||
unmute: () => void;
|
unmute: () => void;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An Embla plugin to take automated actions on media (e.g. pause, unmute, etc).
|
* An Embla plugin to take automated actions on media (e.g. pause, unmute, etc).
|
||||||
* @param userOptions
|
* @param userOptions
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function AutoMediaPlugin(
|
export function AutoMediaPlugin(
|
||||||
userOptions?: AutoMediaPluginOptionsType,
|
userOptions?: AutoMediaPluginOptionsType,
|
||||||
@@ -43,7 +44,12 @@ export function AutoMediaPlugin(
|
|||||||
// slide is selected, so only pause (and not play/unmute) based on carousel
|
// slide is selected, so only pause (and not play/unmute) based on carousel
|
||||||
// events.
|
// events.
|
||||||
carousel.on('destroy', pause);
|
carousel.on('destroy', pause);
|
||||||
carousel.on('select', pausePrevious);
|
if (
|
||||||
|
options.autoPauseCondition &&
|
||||||
|
['all', 'unselected'].includes(options.autoPauseCondition)
|
||||||
|
) {
|
||||||
|
carousel.on('select', pausePrevious);
|
||||||
|
}
|
||||||
carousel.on('destroy', mute);
|
carousel.on('destroy', mute);
|
||||||
carousel.on('select', mutePrevious);
|
carousel.on('select', mutePrevious);
|
||||||
|
|
||||||
@@ -55,7 +61,12 @@ export function AutoMediaPlugin(
|
|||||||
*/
|
*/
|
||||||
function destroy(): void {
|
function destroy(): void {
|
||||||
carousel.off('destroy', pause);
|
carousel.off('destroy', pause);
|
||||||
carousel.off('select', pausePrevious);
|
if (
|
||||||
|
options.autoPauseCondition &&
|
||||||
|
['all', 'unselected'].includes(options.autoPauseCondition)
|
||||||
|
) {
|
||||||
|
carousel.off('select', pausePrevious);
|
||||||
|
}
|
||||||
carousel.off('destroy', mute);
|
carousel.off('destroy', mute);
|
||||||
carousel.off('select', mutePrevious);
|
carousel.off('select', mutePrevious);
|
||||||
|
|
||||||
@@ -65,14 +76,19 @@ export function AutoMediaPlugin(
|
|||||||
/**
|
/**
|
||||||
* Handle document visibility changes.
|
* Handle document visibility changes.
|
||||||
*/
|
*/
|
||||||
function visibilityHandler(): void {
|
function visibilityHandler(): void {
|
||||||
if (document.visibilityState == 'hidden') {
|
if (document.visibilityState == 'hidden') {
|
||||||
pause();
|
if (
|
||||||
|
options.autoPauseCondition &&
|
||||||
|
['all', 'hidden'].includes(options.autoPauseCondition)
|
||||||
|
) {
|
||||||
|
pauseAll();
|
||||||
|
}
|
||||||
mute();
|
mute();
|
||||||
} else if (document.visibilityState == 'visible') {
|
} else if (document.visibilityState == 'visible') {
|
||||||
if (options.autoPlayWhenVisible) {
|
if (options.autoPlayWhenVisible) {
|
||||||
play();
|
play();
|
||||||
}
|
}
|
||||||
if (options.autoUnmuteWhenVisible) {
|
if (options.autoUnmuteWhenVisible) {
|
||||||
unmute();
|
unmute();
|
||||||
}
|
}
|
||||||
@@ -109,6 +125,15 @@ export function AutoMediaPlugin(
|
|||||||
getPlayer(slides[carousel.previousScrollSnap()])?.pause();
|
getPlayer(slides[carousel.previousScrollSnap()])?.pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pause the previous slide.
|
||||||
|
*/
|
||||||
|
function pauseAll(): void {
|
||||||
|
for (const slide of slides) {
|
||||||
|
getPlayer(slide)?.pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unmute the current slide.
|
* Unmute the current slide.
|
||||||
*/
|
*/
|
||||||
@@ -126,7 +151,7 @@ export function AutoMediaPlugin(
|
|||||||
/**
|
/**
|
||||||
* Mute the previous slide.
|
* Mute the previous slide.
|
||||||
*/
|
*/
|
||||||
function mutePrevious(): void {
|
function mutePrevious(): void {
|
||||||
getPlayer(slides[carousel.previousScrollSnap()])?.mute();
|
getPlayer(slides[carousel.previousScrollSnap()])?.mute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -300,6 +300,9 @@ export class FrigateCardLiveCarousel extends FrigateCardMediaCarousel {
|
|||||||
AutoMediaPlugin({
|
AutoMediaPlugin({
|
||||||
playerSelector: 'frigate-card-live-provider',
|
playerSelector: 'frigate-card-live-provider',
|
||||||
autoUnmuteWhenVisible: !!this.liveConfig?.auto_unmute,
|
autoUnmuteWhenVisible: !!this.liveConfig?.auto_unmute,
|
||||||
|
...(this.liveConfig?.auto_pause && {
|
||||||
|
autoPauseCondition: this.liveConfig.auto_pause,
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -282,6 +282,9 @@ export class FrigateCardViewerCarousel extends FrigateCardMediaCarousel {
|
|||||||
playerSelector: 'frigate-card-ha-hls-player',
|
playerSelector: 'frigate-card-ha-hls-player',
|
||||||
autoPlayWhenVisible: !!this.viewerConfig?.auto_play,
|
autoPlayWhenVisible: !!this.viewerConfig?.auto_play,
|
||||||
autoUnmuteWhenVisible: !!this.viewerConfig?.auto_unmute,
|
autoUnmuteWhenVisible: !!this.viewerConfig?.auto_unmute,
|
||||||
|
...(this.viewerConfig?.auto_pause && {
|
||||||
|
autoPauseCondition: this.viewerConfig.auto_pause,
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ export const CONF_EVENT_GALLERY_CONTROLS_THUMBNAILS_SIZE =
|
|||||||
`${CONF_EVENT_GALLERY}.controls.thumbnails.size` as const;
|
`${CONF_EVENT_GALLERY}.controls.thumbnails.size` as const;
|
||||||
|
|
||||||
export const CONF_EVENT_VIEWER = 'event_viewer' 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_PLAY = `${CONF_EVENT_VIEWER}.auto_play` as const;
|
||||||
export const CONF_EVENT_VIEWER_AUTO_UNMUTE = `${CONF_EVENT_VIEWER}.auto_unmute` 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;
|
export const CONF_EVENT_VIEWER_DRAGGABLE = `${CONF_EVENT_VIEWER}.draggable` as const;
|
||||||
@@ -67,6 +68,7 @@ export const CONF_EVENT_VIEWER_CONTROLS_TITLE_DURATION_SECONDS =
|
|||||||
`${CONF_EVENT_VIEWER}.controls.title.duration_seconds` as const;
|
`${CONF_EVENT_VIEWER}.controls.title.duration_seconds` as const;
|
||||||
|
|
||||||
export const CONF_LIVE = 'live' as const;
|
export const CONF_LIVE = 'live' as const;
|
||||||
|
export const CONF_LIVE_AUTO_PAUSE = `${CONF_LIVE}.auto_pause` as const;
|
||||||
export const CONF_LIVE_AUTO_UNMUTE = `${CONF_LIVE}.auto_unmute` as const;
|
export const CONF_LIVE_AUTO_UNMUTE = `${CONF_LIVE}.auto_unmute` as const;
|
||||||
export const CONF_LIVE_CONTROLS_NEXT_PREVIOUS_STYLE =
|
export const CONF_LIVE_CONTROLS_NEXT_PREVIOUS_STYLE =
|
||||||
`${CONF_LIVE}.controls.next_previous.style` as const;
|
`${CONF_LIVE}.controls.next_previous.style` as const;
|
||||||
|
|||||||
+19
-7
@@ -34,6 +34,7 @@ import {
|
|||||||
CONF_EVENT_GALLERY_CONTROLS_THUMBNAILS_SHOW_CONTROLS,
|
CONF_EVENT_GALLERY_CONTROLS_THUMBNAILS_SHOW_CONTROLS,
|
||||||
CONF_EVENT_GALLERY_CONTROLS_THUMBNAILS_SHOW_DETAILS,
|
CONF_EVENT_GALLERY_CONTROLS_THUMBNAILS_SHOW_DETAILS,
|
||||||
CONF_EVENT_GALLERY_CONTROLS_THUMBNAILS_SIZE,
|
CONF_EVENT_GALLERY_CONTROLS_THUMBNAILS_SIZE,
|
||||||
|
CONF_EVENT_VIEWER_AUTO_PAUSE,
|
||||||
CONF_EVENT_VIEWER_AUTO_PLAY,
|
CONF_EVENT_VIEWER_AUTO_PLAY,
|
||||||
CONF_EVENT_VIEWER_AUTO_UNMUTE,
|
CONF_EVENT_VIEWER_AUTO_UNMUTE,
|
||||||
CONF_EVENT_VIEWER_CONTROLS_NEXT_PREVIOUS_SIZE,
|
CONF_EVENT_VIEWER_CONTROLS_NEXT_PREVIOUS_SIZE,
|
||||||
@@ -50,6 +51,7 @@ import {
|
|||||||
CONF_IMAGE_MODE,
|
CONF_IMAGE_MODE,
|
||||||
CONF_IMAGE_REFRESH_SECONDS,
|
CONF_IMAGE_REFRESH_SECONDS,
|
||||||
CONF_IMAGE_URL,
|
CONF_IMAGE_URL,
|
||||||
|
CONF_LIVE_AUTO_PAUSE,
|
||||||
CONF_LIVE_AUTO_UNMUTE,
|
CONF_LIVE_AUTO_UNMUTE,
|
||||||
CONF_LIVE_CONTROLS_NEXT_PREVIOUS_SIZE,
|
CONF_LIVE_CONTROLS_NEXT_PREVIOUS_SIZE,
|
||||||
CONF_LIVE_CONTROLS_NEXT_PREVIOUS_STYLE,
|
CONF_LIVE_CONTROLS_NEXT_PREVIOUS_STYLE,
|
||||||
@@ -349,12 +351,15 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
|
|||||||
{ value: 'auto', label: localize('config.view.dark_modes.auto') },
|
{ value: 'auto', label: localize('config.view.dark_modes.auto') },
|
||||||
];
|
];
|
||||||
|
|
||||||
protected _lazyUnloadConditions: EditorSelectOption[] = [
|
protected _mediaActionConditions: EditorSelectOption[] = [
|
||||||
{ value: '', label: '' },
|
{ value: '', label: '' },
|
||||||
{ value: 'all', label: localize('config.live.lazy_unload_conditions.all') },
|
{ value: 'all', label: localize('config.common.media_action_conditions.all') },
|
||||||
{ value: 'unselected', label: localize('config.live.lazy_unload_conditions.unselected') },
|
{
|
||||||
{ value: 'hidden', label: localize('config.live.lazy_unload_conditions.hidden') },
|
value: 'unselected',
|
||||||
{ value: 'never', label: localize('config.live.lazy_unload_conditions.never') },
|
label: localize('config.common.media_action_conditions.unselected'),
|
||||||
|
},
|
||||||
|
{ value: 'hidden', label: localize('config.common.media_action_conditions.hidden') },
|
||||||
|
{ value: 'never', label: localize('config.common.media_action_conditions.never') },
|
||||||
];
|
];
|
||||||
|
|
||||||
public setConfig(config: RawFrigateCardConfig): void {
|
public setConfig(config: RawFrigateCardConfig): void {
|
||||||
@@ -988,7 +993,6 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
|
|||||||
${this._renderMenuButton('timeline')}
|
${this._renderMenuButton('timeline')}
|
||||||
${this._renderMenuButton('media_player')}
|
${this._renderMenuButton('media_player')}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
`
|
`
|
||||||
: ''}
|
: ''}
|
||||||
${this._renderOptionSetHeader('live')}
|
${this._renderOptionSetHeader('live')}
|
||||||
@@ -1000,7 +1004,11 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
|
|||||||
${this._renderSwitch(CONF_LIVE_LAZY_LOAD, defaults.live.lazy_load)}
|
${this._renderSwitch(CONF_LIVE_LAZY_LOAD, defaults.live.lazy_load)}
|
||||||
${this._renderOptionSelector(
|
${this._renderOptionSelector(
|
||||||
CONF_LIVE_LAZY_UNLOAD,
|
CONF_LIVE_LAZY_UNLOAD,
|
||||||
this._lazyUnloadConditions,
|
this._mediaActionConditions,
|
||||||
|
)}
|
||||||
|
${this._renderOptionSelector(
|
||||||
|
CONF_LIVE_AUTO_PAUSE,
|
||||||
|
this._mediaActionConditions,
|
||||||
)}
|
)}
|
||||||
${this._renderSwitch(CONF_LIVE_AUTO_UNMUTE, defaults.live.auto_unmute)}
|
${this._renderSwitch(CONF_LIVE_AUTO_UNMUTE, defaults.live.auto_unmute)}
|
||||||
${this._renderOptionSelector(
|
${this._renderOptionSelector(
|
||||||
@@ -1073,6 +1081,10 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
|
|||||||
CONF_EVENT_VIEWER_AUTO_UNMUTE,
|
CONF_EVENT_VIEWER_AUTO_UNMUTE,
|
||||||
defaults.event_viewer.auto_unmute,
|
defaults.event_viewer.auto_unmute,
|
||||||
)}
|
)}
|
||||||
|
${this._renderOptionSelector(
|
||||||
|
CONF_EVENT_VIEWER_AUTO_PAUSE,
|
||||||
|
this._mediaActionConditions,
|
||||||
|
)}
|
||||||
${this._renderSwitch(
|
${this._renderSwitch(
|
||||||
CONF_EVENT_VIEWER_DRAGGABLE,
|
CONF_EVENT_VIEWER_DRAGGABLE,
|
||||||
defaults.event_viewer.draggable,
|
defaults.event_viewer.draggable,
|
||||||
|
|||||||
@@ -33,6 +33,14 @@
|
|||||||
},
|
},
|
||||||
"zone": "Frigate zone"
|
"zone": "Frigate zone"
|
||||||
},
|
},
|
||||||
|
"common": {
|
||||||
|
"media_action_conditions": {
|
||||||
|
"all": "All opportunities",
|
||||||
|
"unselected": "On unselection",
|
||||||
|
"hidden": "On browser/tab hiding",
|
||||||
|
"never": "Never"
|
||||||
|
}
|
||||||
|
},
|
||||||
"view": {
|
"view": {
|
||||||
"camera_select": "View for newly selected cameras",
|
"camera_select": "View for newly selected cameras",
|
||||||
"dark_mode": "Dark mode",
|
"dark_mode": "Dark mode",
|
||||||
@@ -68,6 +76,7 @@
|
|||||||
},
|
},
|
||||||
"event_viewer": {
|
"event_viewer": {
|
||||||
"auto_play": "Automatically play media",
|
"auto_play": "Automatically play media",
|
||||||
|
"auto_pause": "Automatically pause media",
|
||||||
"auto_unmute": "Automatically unmute media",
|
"auto_unmute": "Automatically unmute media",
|
||||||
"draggable": "Event Viewer can be dragged/swiped",
|
"draggable": "Event Viewer can be dragged/swiped",
|
||||||
"lazy_load": "Event Viewer media is lazily loaded in carousel",
|
"lazy_load": "Event Viewer media is lazily loaded in carousel",
|
||||||
@@ -117,12 +126,7 @@
|
|||||||
"draggable": "Live cameras view can be dragged/swiped",
|
"draggable": "Live cameras view can be dragged/swiped",
|
||||||
"lazy_load": "Live cameras are lazily loaded",
|
"lazy_load": "Live cameras are lazily loaded",
|
||||||
"lazy_unload": "Live cameras are lazily unloaded",
|
"lazy_unload": "Live cameras are lazily unloaded",
|
||||||
"lazy_unload_conditions": {
|
"auto_pause": "Automatically pause live cameras",
|
||||||
"all": "All opportunities",
|
|
||||||
"unselected": "On unselection",
|
|
||||||
"hidden": "On browser/tab hiding",
|
|
||||||
"never": "Never"
|
|
||||||
},
|
|
||||||
"auto_unmute": "Automatically unmute live cameras",
|
"auto_unmute": "Automatically unmute live cameras",
|
||||||
"transition_effect": "Live camera transition effect",
|
"transition_effect": "Live camera transition effect",
|
||||||
"controls": {
|
"controls": {
|
||||||
|
|||||||
+8
-3
@@ -64,8 +64,9 @@ export const FRIGATE_MENU_PRIORITY_MAX = 100;
|
|||||||
const LIVE_PROVIDERS = ['auto', 'ha', 'frigate-jsmpeg', 'webrtc-card'] as const;
|
const LIVE_PROVIDERS = ['auto', 'ha', 'frigate-jsmpeg', 'webrtc-card'] as const;
|
||||||
export type LiveProvider = typeof LIVE_PROVIDERS[number];
|
export type LiveProvider = typeof LIVE_PROVIDERS[number];
|
||||||
|
|
||||||
const LAZY_UNLOAD_CONDITIONS = ['all', 'unselected', 'hidden', 'never'] as const;
|
const MEDIA_ACTION_CONDITIONS = ['all', 'unselected', 'hidden', 'never'] as const;
|
||||||
export type LazyUnloadCondition = typeof LAZY_UNLOAD_CONDITIONS[number];
|
export type LazyUnloadCondition = typeof MEDIA_ACTION_CONDITIONS[number];
|
||||||
|
export type AutoPauseCondition = typeof MEDIA_ACTION_CONDITIONS[number];
|
||||||
|
|
||||||
export class FrigateCardError extends Error {}
|
export class FrigateCardError extends Error {}
|
||||||
|
|
||||||
@@ -560,6 +561,7 @@ export type TitleControlConfig = z.infer<typeof titleControlConfigSchema>;
|
|||||||
* Live view configuration section.
|
* Live view configuration section.
|
||||||
*/
|
*/
|
||||||
const liveConfigDefault = {
|
const liveConfigDefault = {
|
||||||
|
auto_pause: 'all' as const,
|
||||||
auto_unmute: false,
|
auto_unmute: false,
|
||||||
preload: false,
|
preload: false,
|
||||||
lazy_load: true,
|
lazy_load: true,
|
||||||
@@ -665,10 +667,11 @@ const liveOverridableConfigSchema = z
|
|||||||
const liveConfigSchema = liveOverridableConfigSchema
|
const liveConfigSchema = liveOverridableConfigSchema
|
||||||
.extend({
|
.extend({
|
||||||
// Non-overrideable parameters.
|
// Non-overrideable parameters.
|
||||||
|
auto_pause: z.enum(MEDIA_ACTION_CONDITIONS).default(liveConfigDefault.auto_pause),
|
||||||
auto_unmute: z.boolean().default(liveConfigDefault.auto_unmute),
|
auto_unmute: z.boolean().default(liveConfigDefault.auto_unmute),
|
||||||
preload: z.boolean().default(liveConfigDefault.preload),
|
preload: z.boolean().default(liveConfigDefault.preload),
|
||||||
lazy_load: z.boolean().default(liveConfigDefault.lazy_load),
|
lazy_load: z.boolean().default(liveConfigDefault.lazy_load),
|
||||||
lazy_unload: z.enum(LAZY_UNLOAD_CONDITIONS).default(liveConfigDefault.lazy_unload),
|
lazy_unload: z.enum(MEDIA_ACTION_CONDITIONS).default(liveConfigDefault.lazy_unload),
|
||||||
draggable: z.boolean().default(liveConfigDefault.draggable),
|
draggable: z.boolean().default(liveConfigDefault.draggable),
|
||||||
transition_effect: transitionEffectConfigSchema.default(
|
transition_effect: transitionEffectConfigSchema.default(
|
||||||
liveConfigDefault.transition_effect,
|
liveConfigDefault.transition_effect,
|
||||||
@@ -750,6 +753,7 @@ export type MenuConfig = z.infer<typeof menuConfigSchema>;
|
|||||||
* Event viewer configuration section (clip, snapshot).
|
* Event viewer configuration section (clip, snapshot).
|
||||||
*/
|
*/
|
||||||
const viewerConfigDefault = {
|
const viewerConfigDefault = {
|
||||||
|
auto_pause: 'all' as const,
|
||||||
auto_play: true,
|
auto_play: true,
|
||||||
auto_unmute: false,
|
auto_unmute: false,
|
||||||
lazy_load: true,
|
lazy_load: true,
|
||||||
@@ -786,6 +790,7 @@ export type ViewerNextPreviousControlConfig = z.infer<
|
|||||||
|
|
||||||
const viewerConfigSchema = z
|
const viewerConfigSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
auto_pause: z.enum(MEDIA_ACTION_CONDITIONS).default(viewerConfigDefault.auto_pause),
|
||||||
auto_play: z.boolean().default(viewerConfigDefault.auto_play),
|
auto_play: z.boolean().default(viewerConfigDefault.auto_play),
|
||||||
auto_unmute: z.boolean().default(viewerConfigDefault.auto_unmute),
|
auto_unmute: z.boolean().default(viewerConfigDefault.auto_unmute),
|
||||||
lazy_load: z.boolean().default(viewerConfigDefault.lazy_load),
|
lazy_load: z.boolean().default(viewerConfigDefault.lazy_load),
|
||||||
|
|||||||
Reference in New Issue
Block a user