Initial attempt at auto_pause .

This commit is contained in:
Dermot Duffy
2022-05-08 08:05:33 -07:00
parent 1dcd2c4dc1
commit 66588ee1c6
7 changed files with 80 additions and 26 deletions
+28 -3
View File
@@ -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,7 +18,7 @@ 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).
@@ -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);
if (
options.autoPauseCondition &&
['all', 'unselected'].includes(options.autoPauseCondition)
) {
carousel.on('select', pausePrevious); 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);
if (
options.autoPauseCondition &&
['all', 'unselected'].includes(options.autoPauseCondition)
) {
carousel.off('select', pausePrevious); carousel.off('select', pausePrevious);
}
carousel.off('destroy', mute); carousel.off('destroy', mute);
carousel.off('select', mutePrevious); carousel.off('select', mutePrevious);
@@ -67,7 +78,12 @@ export function AutoMediaPlugin(
*/ */
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) {
@@ -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.
*/ */
+3
View File
@@ -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,
}),
}), }),
]; ];
} }
+3
View File
@@ -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,
}),
}), }),
]; ];
} }
+2
View File
@@ -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
View File
@@ -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,
+10 -6
View File
@@ -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
View File
@@ -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),