New Media Player - Cloned from Android Spotify Notification (#5044)

* Media Player Spotify Clone

* Ellipsis fix

* Style for theme update

* Height now determined by player height

* comments - Also includes Testing with images

* Pushing to resolve balloobs comments ;)

* Add Node Vibrant type

* Update Styles

* Comments

* Reviews

* Lint

* undo readme

* Reviews && Clean up

* Clear Interval

* Animation updates + comments

* small style tweak and comment

* Last little fix

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
Zack Arnett 2020-03-05 21:33:38 -05:00 committed by GitHub
parent 74657ae815
commit 84dc8188c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 876 additions and 219 deletions

View File

@ -19,12 +19,15 @@ This is the repository for the official [Home Assistant](https://home-assistant.
## Frontend development
### Classic environment
A complete guide can be found at the following [link](https://www.home-assistant.io/developers/frontend/). It describes a short guide for the build of project.
### Docker environment
It is possible to compile the project and/or run commands in the development environment having only the [Docker](https://www.docker.com) pre-installed in the system. On the root of project you can do:
* `sh ./script/docker_run.sh build` Build all the project with one command
* `sh ./script/docker_run.sh bash` Open an interactive shell (the same environment generated by the *classic environment*) where you can run commands. This bash work on your project directory and any change on your file is automatically present within your build bash.
- `sh ./script/docker_run.sh build` Build all the project with one command
- `sh ./script/docker_run.sh bash` Open an interactive shell (the same environment generated by the _classic environment_) where you can run commands. This bash work on your project directory and any change on your file is automatically present within your build bash.
**Note**: if you have installed `npm` in addition to the `docker`, you can use the commands `npm run docker_build` and `npm run bash` to get a full build or bash as explained above

View File

@ -70,6 +70,7 @@
"@polymer/paper-tooltip": "^3.0.1",
"@polymer/polymer": "3.1.0",
"@thomasloven/round-slider": "0.3.7",
"@types/resize-observer-browser": "^0.1.3",
"@vaadin/vaadin-combo-box": "^5.0.10",
"@vaadin/vaadin-date-picker": "^4.0.7",
"@webcomponents/shadycss": "^1.9.0",
@ -97,10 +98,12 @@
"mdn-polyfills": "^5.16.0",
"memoize-one": "^5.0.2",
"moment": "^2.24.0",
"node-vibrant": "^3.1.5",
"preact": "^8.4.2",
"preact-compat": "^3.18.4",
"react-big-calendar": "^0.20.4",
"regenerator-runtime": "^0.13.2",
"resize-observer": "^1.0.0",
"roboto-fontface": "^0.10.0",
"superstruct": "^0.6.1",
"tslib": "^1.10.0",

View File

@ -1,6 +1,4 @@
import { HomeAssistant } from "../types";
import { timeCachePromiseFunc } from "../common/util/time-cache-function-promise";
import { HassEntity } from "home-assistant-js-websocket";
export const SUPPORT_PAUSE = 1;
export const SUPPORT_SEEK = 2;
@ -17,30 +15,47 @@ export const SUPPORT_STOP = 4096;
export const SUPPORTS_PLAY = 16384;
export const SUPPORT_SELECT_SOUND_MODE = 65536;
export const OFF_STATES = ["off", "idle"];
export const CONTRAST_RATIO = 3.5;
export interface MediaPlayerThumbnail {
content_type: string;
content: string;
}
export const fetchMediaPlayerThumbnailWithCache = (
hass: HomeAssistant,
entityId: string
) =>
timeCachePromiseFunc(
"_media_playerTmb",
9000,
fetchMediaPlayerThumbnail,
hass,
entityId
);
export const fetchMediaPlayerThumbnail = (
hass: HomeAssistant,
entityId: string
) => {
return hass.callWS<MediaPlayerThumbnail>({
type: "media_player_thumbnail",
entity_id: entityId,
});
export const getCurrentProgress = (stateObj: HassEntity): number => {
let progress = stateObj.attributes.media_position;
progress +=
(Date.now() -
new Date(stateObj.attributes.media_position_updated_at).getTime()) /
1000.0;
return progress;
};
export const computeMediaDescription = (stateObj: HassEntity): string => {
let secondaryTitle: string;
switch (stateObj.attributes.media_content_type) {
case "music":
secondaryTitle = stateObj.attributes.media_artist;
break;
case "playlist":
secondaryTitle = stateObj.attributes.media_playlist;
break;
case "tvshow":
secondaryTitle = stateObj.attributes.media_series_title;
if (stateObj.attributes.media_season) {
secondaryTitle += " S" + stateObj.attributes.media_season;
if (stateObj.attributes.media_episode) {
secondaryTitle += "E" + stateObj.attributes.media_episode;
}
}
break;
default:
secondaryTitle = stateObj.attributes.app_name
? stateObj.attributes.app_name
: "";
}
return secondaryTitle;
};

View File

@ -9,33 +9,48 @@ import {
CSSResult,
} from "lit-element";
import { classMap } from "lit-html/directives/class-map";
import { HassEntity } from "home-assistant-js-websocket";
import { styleMap } from "lit-html/directives/style-map";
import * as Vibrant from "node-vibrant";
import { Palette } from "node-vibrant/lib/color";
import "@polymer/paper-icon-button/paper-icon-button";
import "../../../components/ha-card";
import { MediaControlCardConfig } from "./types";
import { LovelaceCard, LovelaceCardEditor } from "../types";
import { HomeAssistant, MediaEntity } from "../../../types";
import { debounce } from "../../../common/util/debounce";
import { fireEvent } from "../../../common/dom/fire_event";
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
import { computeStateName } from "../../../common/entity/compute_state_name";
import { supportsFeature } from "../../../common/entity/supports-feature";
import { stateIcon } from "../../../common/entity/state_icon";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import { contrast } from "../common/color/contrast";
import { findEntities } from "../common/find-entites";
import { LovelaceConfig } from "../../../data/lovelace";
import { UNAVAILABLE } from "../../../data/entity";
import {
OFF_STATES,
SUPPORT_PAUSE,
SUPPORT_TURN_ON,
SUPPORT_TURN_OFF,
SUPPORT_PREVIOUS_TRACK,
SUPPORT_NEXT_TRACK,
SUPPORTS_PLAY,
fetchMediaPlayerThumbnailWithCache,
SUPPORT_STOP,
SUPPORT_SEEK,
CONTRAST_RATIO,
getCurrentProgress,
computeMediaDescription,
} from "../../../data/media-player";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import { HomeAssistant, MediaEntity } from "../../../types";
import { LovelaceCard, LovelaceCardEditor } from "../types";
import { fireEvent } from "../../../common/dom/fire_event";
import { MediaControlCardConfig } from "./types";
import { UNAVAILABLE } from "../../../data/entity";
import { LovelaceConfig } from "../../../data/lovelace";
import { findEntities } from "../common/find-entites";
import "../../../components/ha-card";
import "../../../components/ha-icon";
function getContrastRatio(
rgb1: [number, number, number],
rgb2: [number, number, number]
): number {
return Math.round((contrast(rgb1, rgb2) + Number.EPSILON) * 100) / 100;
}
@customElement("hui-media-control-card")
export class HuiMediaControlCard extends LitElement implements LovelaceCard {
@ -68,7 +83,24 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
@property() public hass?: HomeAssistant;
@property() private _config?: MediaControlCardConfig;
@property() private _image?: string;
@property() private _foregroundColor?: string;
@property() private _backgroundColor?: string;
@property() private _narrow: boolean = false;
@property() private _veryNarrow: boolean = false;
@property() private _cardHeight: number = 0;
private _progressInterval?: number;
private _resizeObserver?: ResizeObserver;
private _debouncedResizeListener = debounce(
() => {
this._narrow = this.offsetWidth < 350;
this._veryNarrow = this.offsetWidth < 300;
if (this._image) {
this._cardHeight = this.offsetHeight;
}
},
250,
false
);
public getCardSize(): number {
return 3;
@ -82,6 +114,37 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
this._config = { theme: "default", ...config };
}
public connectedCallback(): void {
super.connectedCallback();
if (!this.hass || !this._config) {
return undefined;
}
const stateObj = this.hass.states[this._config.entity] as MediaEntity;
if (!stateObj) {
return undefined;
}
if (
!this._progressInterval &&
this._showProgressBar &&
stateObj.state === "playing"
) {
this._progressInterval = window.setInterval(
() => this.requestUpdate(),
1000
);
}
}
public disconnectedCallback(): void {
if (this._progressInterval) {
clearInterval(this._progressInterval);
this._progressInterval = undefined;
}
}
protected render(): TemplateResult {
if (!this.hass || !this._config) {
return html``;
@ -100,108 +163,164 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
`;
}
const picture = this._image || "../static/images/card_media_player_bg.png";
const imageStyle = {
"background-image": `url(${this.hass.hassUrl(this._image)})`,
width: `${this._cardHeight}px`,
"background-color": `${this._backgroundColor}`,
};
const gradientStyle = {
"background-image": `linear-gradient(to right, ${this._backgroundColor}, transparent)`,
width: `${this._cardHeight}px`,
};
return html`
<ha-card>
<div
class="ratio ${classMap({
class="background ${classMap({
"no-image": !this._image,
off: OFF_STATES.includes(stateObj.state),
})}"
>
<div
class="image"
style="background-image: url(${this.hass.hassUrl(picture)})"
class="color-block"
style="background-color: ${this._backgroundColor}"
></div>
<div
class="caption ${classMap({
unavailable: stateObj.state === UNAVAILABLE,
})}"
>
${this._config!.name ||
computeStateName(this.hass!.states[this._config!.entity])}
<div class="title">
${stateObj.attributes.media_title ||
this.hass.localize(`state.media_player.${stateObj.state}`) ||
this.hass.localize(`state.default.${stateObj.state}`) ||
stateObj.state}
</div>
${this._computeSecondaryTitle(stateObj)}
</div>
</div>
${OFF_STATES.includes(stateObj.state) ||
!stateObj.attributes.media_duration ||
!stateObj.attributes.media_position
? ""
: html`
<paper-progress
.max="${stateObj.attributes.media_duration}"
.value="${stateObj.attributes.media_position}"
class="progress ${classMap({
seek: supportsFeature(stateObj, SUPPORT_SEEK),
})}"
@click=${(e: MouseEvent) => this._handleSeek(e, stateObj)}
></paper-progress>
`}
<div class="controls">
${(stateObj.state === "off" &&
!supportsFeature(stateObj, SUPPORT_TURN_ON)) ||
(stateObj.state === "on" &&
!supportsFeature(stateObj, SUPPORT_TURN_OFF))
class="no-img"
style="background-color: ${this._backgroundColor}"
></div>
<div class="image" style=${styleMap(imageStyle)}></div>
${!this._image
? ""
: html`
<paper-icon-button
icon="hass:power"
.action=${stateObj.state === "off" ? "turn_on" : "turn_off"}
@click=${this._handleClick}
></paper-icon-button>
<div
class="color-gradient"
style=${styleMap(gradientStyle)}
></div>
`}
<div class="playback-controls">
${!supportsFeature(stateObj, SUPPORT_PREVIOUS_TRACK)
</div>
<div
class="player ${classMap({
"no-image": !this._image,
narrow: this._narrow && !this._veryNarrow,
off: OFF_STATES.includes(stateObj.state),
"no-progress": !this._showProgressBar && !this._veryNarrow,
})}"
style="color: ${this._foregroundColor}"
>
<div class="top-info">
<div class="icon-name">
<ha-icon class="icon" .icon="${stateIcon(stateObj)}"></ha-icon>
<div>
${this._config!.name ||
computeStateName(this.hass!.states[this._config!.entity])}
</div>
</div>
<div>
<paper-icon-button
icon="hass:dots-vertical"
class="more-info"
@click=${this._handleMoreInfo}
></paper-icon-button>
</div>
</div>
<div
class="title-controls"
style="padding-right: ${OFF_STATES.includes(stateObj.state)
? 0
: this._cardHeight - 40}px"
>
${OFF_STATES.includes(stateObj.state)
? ""
: html`
<paper-icon-button
icon="hass:skip-previous"
.disabled="${OFF_STATES.includes(stateObj.state)}"
.action=${"media_previous_track"}
@click=${this._handleClick}
></paper-icon-button>
<div class="media-info">
<div class="title">
${stateObj.attributes.media_title ||
computeMediaDescription(stateObj)}
</div>
${!stateObj.attributes.media_title
? ""
: computeMediaDescription(stateObj)}
</div>
`}
${(stateObj.state !== "playing" &&
!supportsFeature(stateObj, SUPPORTS_PLAY)) ||
stateObj.state === UNAVAILABLE ||
(stateObj.state === "playing" &&
!supportsFeature(stateObj, SUPPORT_PAUSE) &&
!supportsFeature(stateObj, SUPPORT_STOP))
${this._veryNarrow && !OFF_STATES.includes(stateObj.state)
? ""
: html`
<paper-icon-button
class="playPauseButton"
.disabled="${OFF_STATES.includes(stateObj.state)}"
.icon=${stateObj.state !== "playing"
? "hass:play"
: supportsFeature(stateObj, SUPPORT_PAUSE)
? "hass:pause"
: "hass:stop"}
.action=${"media_play_pause"}
@click=${this._handleClick}
></paper-icon-button>
`}
${!supportsFeature(stateObj, SUPPORT_NEXT_TRACK)
? ""
: html`
<paper-icon-button
icon="hass:skip-next"
.disabled="${OFF_STATES.includes(stateObj.state)}"
.action=${"media_next_track"}
@click=${this._handleClick}
></paper-icon-button>
<div class="controls">
<div>
${(stateObj.state === "off" &&
!supportsFeature(stateObj, SUPPORT_TURN_ON)) ||
!OFF_STATES.includes(stateObj.state)
? ""
: html`
<paper-icon-button
icon="hass:power"
.action=${stateObj.state === "off"
? "turn_on"
: "turn_off"}
@click=${this._handleClick}
></paper-icon-button>
`}
</div>
${OFF_STATES.includes(stateObj.state)
? ""
: html`
<div class="playback-controls">
${!supportsFeature(stateObj, SUPPORT_PREVIOUS_TRACK)
? ""
: html`
<paper-icon-button
icon="hass:skip-previous"
.action=${"media_previous_track"}
@click=${this._handleClick}
></paper-icon-button>
`}
${(stateObj.state !== "playing" &&
!supportsFeature(stateObj, SUPPORTS_PLAY)) ||
stateObj.state === UNAVAILABLE ||
(stateObj.state === "playing" &&
!supportsFeature(stateObj, SUPPORT_PAUSE) &&
!supportsFeature(stateObj, SUPPORT_STOP))
? ""
: html`
<paper-icon-button
class="playPauseButton"
.icon=${stateObj.state !== "playing"
? "hass:play"
: supportsFeature(stateObj, SUPPORT_PAUSE)
? "hass:pause"
: "hass:stop"}
.action=${"media_play_pause"}
@click=${this._handleClick}
></paper-icon-button>
`}
${!supportsFeature(stateObj, SUPPORT_NEXT_TRACK)
? ""
: html`
<paper-icon-button
icon="hass:skip-next"
.action=${"media_next_track"}
@click=${this._handleClick}
></paper-icon-button>
`}
</div>
`}
</div>
`}
</div>
<paper-icon-button
icon="hass:dots-vertical"
@click=${this._handleMoreInfo}
></paper-icon-button>
${!this._showProgressBar
? ""
: html`
<paper-progress
.max="${stateObj.attributes.media_duration}"
.value="${getCurrentProgress(stateObj)}"
class="progress"
style="--paper-progress-active-color: ${this
._foregroundColor || "var(--accent-color)"}"
@click=${(e: MouseEvent) => this._handleSeek(e, stateObj)}
></paper-progress>
`}
</div>
</ha-card>
`;
@ -211,12 +330,22 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
return hasConfigOrEntityChanged(this, changedProps);
}
protected firstUpdated(): void {
this._attachObserver();
}
protected updated(changedProps: PropertyValues): void {
super.updated(changedProps);
if (!this._config || !this.hass || !changedProps.has("hass")) {
return;
}
const stateObj = this.hass.states[this._config.entity] as MediaEntity;
if (!stateObj) {
return;
}
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
const oldConfig = changedProps.get("_config") as
| MediaControlCardConfig
@ -231,57 +360,89 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
applyThemesOnElement(this, this.hass.themes, this._config.theme);
}
if (
!this._progressInterval &&
this._showProgressBar &&
stateObj.state === "playing"
) {
this._progressInterval = window.setInterval(
() => this.requestUpdate(),
1000
);
} else if (
this._progressInterval &&
(!this._showProgressBar || stateObj.state !== "playing")
) {
clearInterval(this._progressInterval);
this._progressInterval = undefined;
}
const oldImage =
oldHass?.states[this._config.entity]?.attributes.entity_picture_local ||
oldHass?.states[this._config.entity]?.attributes.entity_picture;
const newImage = this.hass.states[this._config.entity]?.attributes
.entity_picture;
if (!newImage || newImage === oldImage) {
this._image = newImage;
if (!this._image) {
this._foregroundColor = undefined;
this._backgroundColor = undefined;
return;
}
if (newImage.substr(0, 1) !== "/") {
this._image = newImage;
if (this._image !== oldImage) {
this._setColors();
return;
}
fetchMediaPlayerThumbnailWithCache(this.hass, this._config.entity)
.then(({ content_type, content }) => {
this._image = `data:${content_type};base64,${content}`;
})
.catch(() => {
this._image = undefined;
});
}
private _computeSecondaryTitle(stateObj: HassEntity): string {
let secondaryTitle: string;
switch (stateObj.attributes.media_content_type) {
case "music":
secondaryTitle = stateObj.attributes.media_artist;
break;
case "playlist":
secondaryTitle = stateObj.attributes.media_playlist;
break;
case "tvshow":
secondaryTitle = stateObj.attributes.media_series_title;
if (stateObj.attributes.media_season) {
secondaryTitle += " S" + stateObj.attributes.media_season;
if (stateObj.attributes.media_episode) {
secondaryTitle += "E" + stateObj.attributes.media_episode;
}
}
break;
default:
secondaryTitle = stateObj.attributes.app_name
? stateObj.attributes.app_name
: "";
private get _image() {
if (!this.hass || !this._config) {
return undefined;
}
return secondaryTitle;
const stateObj = this.hass.states[this._config.entity] as MediaEntity;
if (!stateObj) {
return undefined;
}
return (
stateObj.attributes.entity_picture_local ||
stateObj.attributes.entity_picture
);
}
private get _showProgressBar() {
if (!this.hass || !this._config) {
return false;
}
const stateObj = this.hass.states[this._config.entity] as MediaEntity;
if (!stateObj) {
return false;
}
return (
!OFF_STATES.includes(stateObj.state) &&
stateObj.attributes.media_duration &&
stateObj.attributes.media_position &&
!this._narrow
);
}
private _attachObserver(): void {
if (typeof ResizeObserver !== "function") {
import("resize-observer").then((modules) => {
modules.install();
this._attachObserver();
});
return;
}
this._resizeObserver = new ResizeObserver(() =>
this._debouncedResizeListener()
);
this._resizeObserver.observe(this);
}
private _handleMoreInfo(): void {
@ -301,7 +462,11 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
return;
}
const percent = e.offsetX / this.offsetWidth;
const progressWidth = (this.shadowRoot!.querySelector(
"paper-progress"
) as HTMLElement).offsetWidth;
const percent = e.offsetX / progressWidth;
const position = (e.currentTarget! as any).max * percent;
this.hass!.callService("media_player", "media_seek", {
@ -310,50 +475,137 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
});
}
private _setColors(): void {
if (!this._image) {
return;
}
Vibrant.from(this._image)
.quality(1)
.getPalette()
.then((palette: Palette) => {
if (!palette.DarkMuted) {
this._foregroundColor = undefined;
this._backgroundColor = undefined;
return;
}
this._backgroundColor = palette.DarkMuted.getHex();
if (
!palette.Vibrant ||
getContrastRatio(
palette.Vibrant.getRgb(),
palette.DarkMuted.getRgb()
) < CONTRAST_RATIO
) {
this._foregroundColor = palette.DarkMuted.getBodyTextColor();
return;
}
this._foregroundColor = palette.Vibrant.getHex();
})
.catch((err: any) => {
// tslint:disable-next-line:no-console
console.error("Error getting Image Colors", err);
this._foregroundColor = undefined;
this._backgroundColor = undefined;
});
}
static get styles(): CSSResult {
return css`
.ratio {
position: relative;
width: 100%;
height: 0;
padding-bottom: 56.25%;
transition: padding-bottom 0.8s;
ha-card {
overflow: hidden;
}
.image {
.background {
display: flex;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: block;
transition: filter 0.2s linear;
background-position: center center;
width: 100%;
transition: filter 0.8s;
}
.color-block {
background-color: var(--primary-color);
transition: background-color 0.8s;
width: 100%;
}
.color-gradient {
position: absolute;
background-image: linear-gradient(
to right,
var(--primary-color),
transparent
);
height: 100%;
right: 0;
opacity: 1;
transition: width 0.8s, opacity 0.8s linear 0.8s;
}
.image {
background-color: var(--primary-color);
background-position: center;
background-size: cover;
}
.no-image {
padding-bottom: 88px;
}
.no-image > .image {
background-position: center center;
background-repeat: no-repeat;
position: absolute;
right: 0;
height: 100%;
opacity: 1;
transition: width 0.8s, background-image 0.8s, background-color 0.8s,
background-size 0.8s, opacity 0.8s linear 0.8s;
}
.no-img {
background-color: var(--primary-color);
background-size: initial;
background-repeat: no-repeat;
background-position: center center;
padding-bottom: 0;
position: absolute;
right: 0;
height: 100%;
background-image: url("../static/images/card_media_player_bg.png");
width: 50%;
transition: opacity 0.8s, background-color 0.8s;
}
.no-image > .caption {
background-color: initial;
box-sizing: border-box;
height: 88px;
.off .image,
.off .color-gradient {
opacity: 0;
transition: opacity 0s, width 0.8s;
width: 0;
}
.background:not(.off):not(.no-image) .no-img {
opacity: 0;
}
.player {
position: relative;
padding: 16px;
color: var(--text-primary-color);
transition-property: color, padding;
transition-duration: 0.4s;
}
.icon {
width: 18px;
}
.controls {
padding: 8px;
padding: 8px 8px 8px 0;
display: flex;
justify-content: space-between;
justify-content: flex-start;
align-items: center;
transition: padding, color;
transition-duration: 0.4s;
margin-left: -12px;
}
.controls > div {
@ -366,48 +618,45 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
height: 44px;
}
paper-icon-button {
opacity: var(--dark-primary-opacity);
}
paper-icon-button[disabled] {
opacity: var(--dark-disabled-opacity);
}
.playPauseButton {
width: 56px !important;
height: 56px !important;
background-color: var(--primary-color);
color: white;
border-radius: 50%;
padding: 8px;
transition: background-color 0.5s;
}
.playPauseButton[disabled] {
background-color: rgba(0, 0, 0, var(--dark-disabled-opacity));
.top-info {
display: flex;
justify-content: space-between;
}
.caption {
.icon-name {
display: flex;
height: fit-content;
align-items: center;
}
.icon-name ha-icon {
padding-right: 8px;
}
.more-info {
position: absolute;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, var(--dark-secondary-opacity));
padding: 8px 16px;
font-size: 14px;
font-weight: 500;
color: white;
transition: background-color 0.5s;
top: 8px;
right: 0px;
}
.caption.unavailable {
background-color: rgba(0, 0, 0, var(--dark-secondary-opacity));
.media-info {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.title-controls {
padding-top: 16px;
}
.title {
font-size: 1.2em;
margin: 8px 0 4px;
margin: 0px 0 4px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
@ -416,13 +665,46 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
.progress {
width: 100%;
height: var(--paper-progress-height, 4px);
margin-top: calc(-1 * var(--paper-progress-height, 4px));
--paper-progress-active-color: var(--accent-color);
margin-top: 4px;
border-radius: calc(var(--paper-progress-height, 4px) / 2);
--paper-progress-container-color: rgba(200, 200, 200, 0.5);
}
.seek:hover {
--paper-progress-height: 8px;
.no-image .controls {
padding: 0;
}
.off.background {
filter: grayscale(1);
}
.off .controls paper-icon-button {
width: 55px;
height: 55px;
}
.off.player,
.narrow.player {
padding-bottom: 8px !important;
}
.narrow .controls,
.no-progress .controls {
padding-bottom: 0;
}
.narrow paper-icon-button {
width: 40px;
height: 40px;
}
.narrow .playPauseButton {
width: 50px !important;
height: 50px !important;
}
.no-progress.player {
padding-bottom: 0px;
}
`;
}

View File

@ -0,0 +1,12 @@
import { luminanace } from "./luminanace";
export const contrast = (
rgb1: [number, number, number],
rgb2: [number, number, number]
): number => {
const lum1 = luminanace(...rgb1);
const lum2 = luminanace(...rgb2);
const brightest = Math.max(lum1, lum2);
const darkest = Math.min(lum1, lum2);
return (brightest + 0.05) / (darkest + 0.05);
};

View File

@ -0,0 +1,7 @@
export const luminanace = (r: number, g: number, b: number): number => {
const a = [r, g, b].map((v) => {
v /= 255;
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
});
return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
};

View File

@ -207,6 +207,8 @@ export type MediaEntity = HassEntityBase & {
media_duration: number;
media_position: number;
media_title: string;
icon?: string;
entity_picture_local?: string;
};
};

4
src/types/node-vibrant.d.ts vendored Normal file
View File

@ -0,0 +1,4 @@
declare module "node-vibrant" {
export = Vibrant;
}
declare var Vibrant: Any;

333
yarn.lock
View File

@ -1248,6 +1248,13 @@
dependencies:
regenerator-runtime "^0.13.2"
"@babel/runtime@^7.7.2":
version "7.8.4"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.8.4.tgz#d79f5a2040f7caa24d53e563aad49cbc05581308"
integrity sha512-neAp3zt80trRVBI1x0azq6c57aNBqYZH8KhMm3TaB7wEI5Q4A2SHfBHE8w9gOhI/lrqxtEbXZgQIrHP+wvSGwQ==
dependencies:
regenerator-runtime "^0.13.2"
"@babel/template@^7.1.0", "@babel/template@^7.4.4", "@babel/template@^7.6.0":
version "7.6.0"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.6.0.tgz#7f0159c7f5012230dad64cca42ec9bdb5c9536e6"
@ -1330,6 +1337,113 @@
dependencies:
base64-js "^1.3.0"
"@jimp/bmp@^0.9.3":
version "0.9.3"
resolved "https://registry.yarnpkg.com/@jimp/bmp/-/bmp-0.9.3.tgz#98eafc81674ce750f428ac9380007f1a4e90255e"
integrity sha512-wXZYccgGQAsIK8DZX0wZE3gbSd2mL2+eheSJMts6I5hQjxhVRZd1Gwu425nUQGzfKCOgKYTW0nLv7/8OoOTTkw==
dependencies:
"@babel/runtime" "^7.7.2"
"@jimp/utils" "^0.9.3"
bmp-js "^0.1.0"
core-js "^3.4.1"
"@jimp/core@^0.9.3":
version "0.9.3"
resolved "https://registry.yarnpkg.com/@jimp/core/-/core-0.9.3.tgz#bffbf955c046569bf4b682b575228e31bb41e445"
integrity sha512-kB9lvst1QhgYOC963SAuPgv+DdVfxTProphrSffAAoo5eLeQab/Ca3ZUeX1E/SnLSr+NGVnNCd8c9gyuKDiENg==
dependencies:
"@babel/runtime" "^7.7.2"
"@jimp/utils" "^0.9.3"
any-base "^1.1.0"
buffer "^5.2.0"
core-js "^3.4.1"
exif-parser "^0.1.12"
file-type "^9.0.0"
load-bmfont "^1.3.1"
mkdirp "0.5.1"
phin "^2.9.1"
pixelmatch "^4.0.2"
tinycolor2 "^1.4.1"
"@jimp/custom@^0.9.3":
version "0.9.3"
resolved "https://registry.yarnpkg.com/@jimp/custom/-/custom-0.9.3.tgz#b49dfe1d6b24e62fd4101a7db77104024c8d97e8"
integrity sha512-2E7yabQMeqjcK8+ZFu3Ja5cWyrB0zv/pmzNSDg/BBPJ59HE0fj/qcERAz6VklcjHUYRUfmE5uODsb+4DE0o/YQ==
dependencies:
"@babel/runtime" "^7.7.2"
"@jimp/core" "^0.9.3"
core-js "^3.4.1"
"@jimp/gif@^0.9.3":
version "0.9.3"
resolved "https://registry.yarnpkg.com/@jimp/gif/-/gif-0.9.3.tgz#b2b1a519092f94a913a955f252996f9a968930db"
integrity sha512-DshKgMQ8lXorI/xTRyeRkZqZ3JqgnL2aGYAhx0SkAunyHgXji27chmrOGj/6KVDBucrDf/6mSexnSoUDnlWrfA==
dependencies:
"@babel/runtime" "^7.7.2"
"@jimp/utils" "^0.9.3"
core-js "^3.4.1"
omggif "^1.0.9"
"@jimp/jpeg@^0.9.3":
version "0.9.3"
resolved "https://registry.yarnpkg.com/@jimp/jpeg/-/jpeg-0.9.3.tgz#a759cb3bccf3cb163166873b9bdc0c949c5991b5"
integrity sha512-AJzcTJXfN9BHtpzAbICwR3+GoH0pSr6OYXbAS6yuKwz+xVn9UHrEjQb74CIzIRqrT/VWcIKg29cMQxgokzWY7w==
dependencies:
"@babel/runtime" "^7.7.2"
"@jimp/utils" "^0.9.3"
core-js "^3.4.1"
jpeg-js "^0.3.4"
"@jimp/plugin-resize@^0.9.3":
version "0.9.3"
resolved "https://registry.yarnpkg.com/@jimp/plugin-resize/-/plugin-resize-0.9.3.tgz#916abd57c4f9b426984354c77555ade1efda7a82"
integrity sha512-YzqVE8QoDIZpVuI52v+WejwEjEEiJfNFviQfprfm5af7uSSseZgDw1sJ0koqAu+liMSY+Ewp79v2SDrKoJKqtg==
dependencies:
"@babel/runtime" "^7.7.2"
"@jimp/utils" "^0.9.3"
core-js "^3.4.1"
"@jimp/png@^0.9.3":
version "0.9.3"
resolved "https://registry.yarnpkg.com/@jimp/png/-/png-0.9.3.tgz#5c1bbb89b32e2332891a13efdb423e87287a8321"
integrity sha512-LJXUemDTSbTGAGEp9hNQH0uTRSB8gYeE6FsfT3M00oZincu6/WzDzl0P8E95rMjNxZqAihdTyOP3+kcrbbqX+w==
dependencies:
"@babel/runtime" "^7.7.2"
"@jimp/utils" "^0.9.3"
core-js "^3.4.1"
pngjs "^3.3.3"
"@jimp/tiff@^0.9.3":
version "0.9.3"
resolved "https://registry.yarnpkg.com/@jimp/tiff/-/tiff-0.9.3.tgz#a4498c0616fb24034f5512b159b75b0aea389e9c"
integrity sha512-w9H6dT+GDHN//Srsv27JhRn7R2byzUahOGfFw7KpIn95jg0ogcxjKTo/RAGQC56sr4U092e4Npl7E85Lt934WQ==
dependencies:
"@babel/runtime" "^7.7.2"
core-js "^3.4.1"
utif "^2.0.1"
"@jimp/types@^0.9.3":
version "0.9.3"
resolved "https://registry.yarnpkg.com/@jimp/types/-/types-0.9.3.tgz#75337245a1a8c7c84a414beca3cfeded338c0ef1"
integrity sha512-hUJKoT2IhnbO/trxNWzN19n8g+p7aKbM1R+71n4wMZnD41PzrVtz+sBBCdB+JCjBJs/i7fJt4d9z0i3Xe8m7Zw==
dependencies:
"@babel/runtime" "^7.7.2"
"@jimp/bmp" "^0.9.3"
"@jimp/gif" "^0.9.3"
"@jimp/jpeg" "^0.9.3"
"@jimp/png" "^0.9.3"
"@jimp/tiff" "^0.9.3"
core-js "^3.4.1"
timm "^1.6.1"
"@jimp/utils@^0.9.3":
version "0.9.3"
resolved "https://registry.yarnpkg.com/@jimp/utils/-/utils-0.9.3.tgz#fd7af0d1138febbeacc841be4b802218444ce088"
integrity sha512-9D2Of6BcjYONtl77YfmU2y5aRMLe0/O2e2aQvfCxdNwD33jRdwNdN4i3m73dpiClNquApIjL4nYGhTixA4UstA==
dependencies:
"@babel/runtime" "^7.7.2"
core-js "^3.4.1"
"@material/animation@^5.0.0":
version "5.0.0"
resolved "https://registry.yarnpkg.com/@material/animation/-/animation-5.0.0.tgz#55924a02587173e5af6570bcb375dada17f7cf68"
@ -2470,6 +2584,11 @@
dependencies:
"@types/geojson" "*"
"@types/lodash@^4.14.53":
version "4.14.149"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.149.tgz#1342d63d948c6062838fbf961012f74d4e638440"
integrity sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ==
"@types/memoize-one@4.1.0":
version "4.1.0"
resolved "https://registry.yarnpkg.com/@types/memoize-one/-/memoize-one-4.1.0.tgz#62119f26055b3193ae43ca1882c5b29b88b71ece"
@ -2510,6 +2629,11 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-11.12.1.tgz#d90123f6c61fdf2f7cddd286ddae891586dd3488"
integrity sha512-sKDlqv6COJrR7ar0+GqqhrXQDzQlMcqMnF2iEU6m9hLo8kxozoAGUazwPyELHlRVmjsbvlnGXjnzyptSXVmceA==
"@types/node@^10.11.7":
version "10.17.17"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.17.tgz#7a183163a9e6ff720d86502db23ba4aade5999b8"
integrity sha512-gpNnRnZP3VWzzj5k3qrpRC6Rk3H/uclhAVo1aIvwzK5p5cOrs9yEyQ8H/HBsBY0u5rrWxXEiVPQ0dEB6pkjE8Q==
"@types/node@^4.0.30":
version "4.9.3"
resolved "https://registry.yarnpkg.com/@types/node/-/node-4.9.3.tgz#a24697a8157ab517996afe0c88fa716550ae419a"
@ -2551,6 +2675,11 @@
resolved "https://registry.yarnpkg.com/@types/relateurl/-/relateurl-0.2.28.tgz#6bda7db8653fa62643f5ee69e9f69c11a392e3a6"
integrity sha1-a9p9uGU/piZD9e5p6facEaOS46Y=
"@types/resize-observer-browser@^0.1.3":
version "0.1.3"
resolved "https://registry.yarnpkg.com/@types/resize-observer-browser/-/resize-observer-browser-0.1.3.tgz#5cca2445e6fc34a380760bd6ef8c492863469c47"
integrity sha512-3tGjLIDH8L57fWOfC7NVn/BbGQD7pXwbkk2+8Z4hK/S7kOIv1MUN4nkKjfx0qg4ctkukjzp3Bgr/Z+Hq5ZQZTQ==
"@types/resolve@0.0.6":
version "0.0.6"
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.6.tgz#0bd2f236c2e1cebb98b79885df57edd71a8d770e"
@ -3167,6 +3296,11 @@ ansi-wrap@0.1.0, ansi-wrap@^0.1.0:
resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf"
integrity sha1-qCJQ3bABXponyoLoLqYDu/pF768=
any-base@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/any-base/-/any-base-1.1.0.tgz#ae101a62bc08a597b4c9ab5b7089d456630549fe"
integrity sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg==
any-observable@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b"
@ -4004,6 +4138,11 @@ bluebird@^3.5.5:
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f"
integrity sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==
bmp-js@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/bmp-js/-/bmp-js-0.1.0.tgz#e05a63f796a6c1ff25f4771ec7adadc148c07233"
integrity sha1-4Fpj95amwf8l9Hcex62twUjAcjM=
bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
version "4.11.8"
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"
@ -4226,6 +4365,11 @@ buffer-crc32@^0.2.1, buffer-crc32@~0.2.3:
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=
buffer-equal@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-0.0.1.tgz#91bc74b11ea405bc916bc6aa908faafa5b4aac4b"
integrity sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs=
buffer-equal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-1.0.0.tgz#59616b498304d556abd466966b22eeda3eca5fbe"
@ -4268,6 +4412,14 @@ buffer@^5.1.0:
base64-js "^1.0.2"
ieee754 "^1.1.4"
buffer@^5.2.0:
version "5.4.3"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.4.3.tgz#3fbc9c69eb713d323e3fc1a895eee0710c072115"
integrity sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==
dependencies:
base64-js "^1.0.2"
ieee754 "^1.1.4"
builtin-modules@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
@ -5089,6 +5241,11 @@ core-js@^2.4.0:
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.5.tgz#44bc8d249e7fb2ff5d00e0341a7ffb94fbf67895"
integrity sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==
core-js@^3.4.1:
version "3.6.4"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.4.tgz#440a83536b458114b9cb2ac1580ba377dc470647"
integrity sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw==
core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
@ -5664,6 +5821,11 @@ dom-urls@^1.1.0:
dependencies:
urijs "^1.16.1"
dom-walk@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018"
integrity sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=
dom5@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/dom5/-/dom5-3.0.1.tgz#cdfc7331f376e284bf379e6ea054afc136702944"
@ -6292,6 +6454,11 @@ execa@^1.0.0:
signal-exit "^3.0.0"
strip-eof "^1.0.0"
exif-parser@^0.1.12:
version "0.1.12"
resolved "https://registry.yarnpkg.com/exif-parser/-/exif-parser-0.1.12.tgz#58a9d2d72c02c1f6f02a0ef4a9166272b7760922"
integrity sha1-WKnS1ywCwfbwKg70qRZicrd2CSI=
expand-brackets@^0.1.4:
version "0.1.5"
resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
@ -6563,6 +6730,11 @@ file-entry-cache@^5.0.1:
dependencies:
flat-cache "^2.0.1"
file-type@^9.0.0:
version "9.0.0"
resolved "https://registry.yarnpkg.com/file-type/-/file-type-9.0.0.tgz#a68d5ad07f486414dfb2c8866f73161946714a18"
integrity sha512-Qe/5NJrgIOlwijpq3B7BEpzPFcgzggOTagZmkXQY4LA6bsXKTUstK7Wp12lEJ/mLKTpvIZxmIuRcLYWT6ov9lw==
filename-regex@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
@ -7152,6 +7324,14 @@ global-prefix@^3.0.0:
kind-of "^6.0.2"
which "^1.3.1"
global@~4.3.0:
version "4.3.2"
resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f"
integrity sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=
dependencies:
min-document "^2.19.0"
process "~0.5.1"
globals@^11.1.0, globals@^11.7.0:
version "11.11.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-11.11.0.tgz#dcf93757fa2de5486fbeed7118538adf789e9c2e"
@ -8108,6 +8288,11 @@ is-fullwidth-code-point@^2.0.0:
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
is-function@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5"
integrity sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU=
is-glob@^2.0.0, is-glob@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
@ -8367,6 +8552,11 @@ joi@^14.3.1:
isemail "3.x.x"
topo "3.x.x"
jpeg-js@^0.3.4:
version "0.3.7"
resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.3.7.tgz#471a89d06011640592d314158608690172b1028d"
integrity sha512-9IXdWudL61npZjvLuVe/ktHiA41iE8qFyLB+4VDTblEsWBzeg8WQTlktdUK4CdncUqtUgUg0bbOmTE2bKBKaBQ==
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@ -8762,6 +8952,20 @@ lit-virtualizer@^0.4.2:
resize-observer-polyfill "^1.5.1"
tslib "^1.10.0"
load-bmfont@^1.3.1:
version "1.4.0"
resolved "https://registry.yarnpkg.com/load-bmfont/-/load-bmfont-1.4.0.tgz#75f17070b14a8c785fe7f5bee2e6fd4f98093b6b"
integrity sha512-kT63aTAlNhZARowaNYcY29Fn/QYkc52M3l6V1ifRcPewg2lvUZDAj7R6dXjOL9D0sict76op3T5+odumDSF81g==
dependencies:
buffer-equal "0.0.1"
mime "^1.3.4"
parse-bmfont-ascii "^1.0.3"
parse-bmfont-binary "^1.0.5"
parse-bmfont-xml "^1.1.4"
phin "^2.9.1"
xhr "^2.0.1"
xtend "^4.0.0"
load-json-file@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
@ -9374,7 +9578,7 @@ mime@1.4.1:
resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==
mime@1.6.0:
mime@1.6.0, mime@^1.3.4:
version "1.6.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
@ -9399,6 +9603,13 @@ mimic-fn@^2.0.0:
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.0.0.tgz#0913ff0b121db44ef5848242c38bbb35d44cabde"
integrity sha512-jbex9Yd/3lmICXwYT6gA/j2mNQGU48wCh/VzRd+/Y/PjYQtlg1gLMdZqvu9s/xH7qKvngxRObl56XZR609IMbA==
min-document@^2.19.0:
version "2.19.0"
resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685"
integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=
dependencies:
dom-walk "^0.1.0"
minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
@ -9801,6 +10012,19 @@ node-releases@^1.1.49:
dependencies:
semver "^6.3.0"
node-vibrant@^3.1.5:
version "3.1.5"
resolved "https://registry.yarnpkg.com/node-vibrant/-/node-vibrant-3.1.5.tgz#8729bf35aabd54cd2eccbfadf22124ab4e1305b0"
integrity sha512-Gk+iyBzPSN1SF5qL818QaBtuA38206Z8iPNa0PcLUPyIbZL4+i14VmYxkGCL0n/5Q1721CRSktqtACgkx7Qodg==
dependencies:
"@jimp/custom" "^0.9.3"
"@jimp/plugin-resize" "^0.9.3"
"@jimp/types" "^0.9.3"
"@types/lodash" "^4.14.53"
"@types/node" "^10.11.7"
lodash "^4.17.4"
url "^0.11.0"
nomnom@^1.8.1:
version "1.8.1"
resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.8.1.tgz#2151f722472ba79e50a76fc125bb8c8f2e4dc2a7"
@ -10034,6 +10258,11 @@ obuf@^1.0.0, obuf@^1.1.1, obuf@^1.1.2:
resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e"
integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==
omggif@^1.0.9:
version "1.0.10"
resolved "https://registry.yarnpkg.com/omggif/-/omggif-1.0.10.tgz#ddaaf90d4a42f532e9e7cb3a95ecdd47f17c7b19"
integrity sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==
on-finished@^2.3.0, on-finished@~2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
@ -10240,6 +10469,11 @@ package-json@^4.0.0:
registry-url "^3.0.3"
semver "^5.1.0"
pako@^1.0.5:
version "1.0.11"
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
pako@~1.0.5:
version "1.0.10"
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732"
@ -10280,6 +10514,24 @@ parse-asn1@^5.0.0:
pbkdf2 "^3.0.3"
safe-buffer "^5.1.1"
parse-bmfont-ascii@^1.0.3:
version "1.0.6"
resolved "https://registry.yarnpkg.com/parse-bmfont-ascii/-/parse-bmfont-ascii-1.0.6.tgz#11ac3c3ff58f7c2020ab22769079108d4dfa0285"
integrity sha1-Eaw8P/WPfCAgqyJ2kHkQjU36AoU=
parse-bmfont-binary@^1.0.5:
version "1.0.6"
resolved "https://registry.yarnpkg.com/parse-bmfont-binary/-/parse-bmfont-binary-1.0.6.tgz#d038b476d3e9dd9db1e11a0b0e53a22792b69006"
integrity sha1-0Di0dtPp3Z2x4RoLDlOiJ5K2kAY=
parse-bmfont-xml@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/parse-bmfont-xml/-/parse-bmfont-xml-1.1.4.tgz#015319797e3e12f9e739c4d513872cd2fa35f389"
integrity sha512-bjnliEOmGv3y1aMEfREMBJ9tfL3WR0i0CKPj61DnSLaoxWR3nLrsQrEbCId/8rF4NyRF0cCqisSVXyQYWM+mCQ==
dependencies:
xml-parse-from-string "^1.0.0"
xml2js "^0.4.5"
parse-filepath@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.2.tgz#a632127f53aaf3d15876f5872f3ffac763d6c891"
@ -10299,6 +10551,11 @@ parse-glob@^3.0.4:
is-extglob "^1.0.0"
is-glob "^2.0.0"
parse-headers@^2.0.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.3.tgz#5e8e7512383d140ba02f0c7aa9f49b4399c92515"
integrity sha512-QhhZ+DCCit2Coi2vmAKbq5RGTRcQUOE2+REgv8vdyu7MnYx2eZztegqtTx99TZ86GTIwqiy3+4nQTWZ2tgmdCA==
parse-json@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
@ -10493,6 +10750,11 @@ performance-now@^2.1.0:
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
phin@^2.9.1:
version "2.9.3"
resolved "https://registry.yarnpkg.com/phin/-/phin-2.9.3.tgz#f9b6ac10a035636fb65dfc576aaaa17b8743125c"
integrity sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA==
pify@^2.0.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
@ -10520,6 +10782,13 @@ pinkie@^2.0.0:
resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
pixelmatch@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-4.0.2.tgz#8f47dcec5011b477b67db03c243bc1f3085e8854"
integrity sha1-j0fc7FARtHe2fbA8JDvB8wheiFQ=
dependencies:
pngjs "^3.0.0"
pkg-dir@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b"
@ -10580,6 +10849,11 @@ plylog@^1.0.0:
winston "^3.0.0"
winston-transport "^4.2.0"
pngjs@^3.0.0, pngjs@^3.3.3:
version "3.4.0"
resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f"
integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==
polymer-analyzer@^3.1.3, polymer-analyzer@^3.2.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/polymer-analyzer/-/polymer-analyzer-3.2.2.tgz#6f2014c423663bcaecbee0fc4e07e12710bbd6bf"
@ -10886,6 +11160,11 @@ process@^0.11.10:
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI=
process@~0.5.1:
version "0.5.2"
resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf"
integrity sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=
progress@2.0.3, progress@^2.0.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
@ -11525,6 +11804,11 @@ resize-observer-polyfill@^1.5.1:
resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==
resize-observer@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/resize-observer/-/resize-observer-1.0.0.tgz#4f8380b73b411af4ed7d916fe85a2d59900e71ef"
integrity sha512-D7UFShDm2TgrEDEyeg+/tTEbvOgPWlvPAfJtxiKp+qutu6HowmcGJKjECgGru0PPDIj3SAucn3ZPpOx54fF7DQ==
resolve-cwd@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"
@ -11694,7 +11978,7 @@ sauce-connect-launcher@^1.0.0:
lodash "^4.16.6"
rimraf "^2.5.4"
sax@^1.2.4:
sax@>=0.6.0, sax@^1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
@ -12871,6 +13155,16 @@ timers-browserify@^2.0.4:
dependencies:
setimmediate "^1.0.4"
timm@^1.6.1:
version "1.6.2"
resolved "https://registry.yarnpkg.com/timm/-/timm-1.6.2.tgz#dfd8c6719f7ba1fcfc6295a32670a1c6d166c0bd"
integrity sha512-IH3DYDL1wMUwmIlVmMrmesw5lZD6N+ZOAFWEyLrtpoL9Bcrs9u7M/vyOnHzDD2SMs4irLkVjqxZbHrXStS/Nmw==
tinycolor2@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8"
integrity sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g=
tmp@^0.0.33:
version "0.0.33"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
@ -13395,6 +13689,13 @@ use@^3.1.0:
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
utif@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/utif/-/utif-2.0.1.tgz#9e1582d9bbd20011a6588548ed3266298e711759"
integrity sha512-Z/S1fNKCicQTf375lIP9G8Sa1H/phcysstNrrSdZKj1f9g58J4NMgb5IgiEZN9/nLMPDwF0W7hdOe9Qq2IYoLg==
dependencies:
pako "^1.0.5"
util-deprecate@^1.0.1, util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
@ -14182,11 +14483,39 @@ xdg-basedir@^3.0.0:
resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4"
integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=
xhr@^2.0.1:
version "2.5.0"
resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.5.0.tgz#bed8d1676d5ca36108667692b74b316c496e49dd"
integrity sha512-4nlO/14t3BNUZRXIXfXe+3N6w3s1KoxcJUUURctd64BLRe67E4gRwp4PjywtDY72fXpZ1y6Ch0VZQRY/gMPzzQ==
dependencies:
global "~4.3.0"
is-function "^1.0.1"
parse-headers "^2.0.0"
xtend "^4.0.0"
xml-parse-from-string@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz#a9029e929d3dbcded169f3c6e28238d95a5d5a28"
integrity sha1-qQKekp09vN7RafPG4oI42VpdWig=
xml2js@^0.4.5:
version "0.4.23"
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66"
integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==
dependencies:
sax ">=0.6.0"
xmlbuilder "~11.0.0"
xmlbuilder@8.2.2:
version "8.2.2"
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-8.2.2.tgz#69248673410b4ba42e1a6136551d2922335aa773"
integrity sha1-aSSGc0ELS6QuGmE2VR0pIjNap3M=
xmlbuilder@~11.0.0:
version "11.0.1"
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3"
integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==
xmldom@0.1.x:
version "0.1.27"
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9"