Spotify container

This commit is contained in:
Daniel Kluge 2022-05-12 18:48:40 +02:00
parent a1300e851d
commit 1e90ecf826
6 changed files with 102 additions and 20 deletions

30
package-lock.json generated
View File

@ -10,6 +10,7 @@
"license": "GPL-3.0-only",
"dependencies": {
"buffer": "^6.0.3",
"fast-average-color": "^7.1.0",
"fast-xml-parser": "^4.0.0-beta.8",
"gatsby": "^4.4.0",
"gatsby-plugin-react-svg": "^3.1.0",
@ -2767,6 +2768,11 @@
"node": ">= 6"
}
},
"node_modules/@types/offscreencanvas": {
"version": "2019.6.4",
"resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.6.4.tgz",
"integrity": "sha512-u8SAgdZ8ROtkTF+mfZGOscl0or6BSj9A4g37e6nvxDc+YB/oDut0wHkK2PBBiC2bNR8TS0CPV+1gAk4fNisr1Q=="
},
"node_modules/@types/parse-json": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
@ -7475,6 +7481,17 @@
"url": "https://github.com/sponsors/jaydenseric"
}
},
"node_modules/fast-average-color": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/fast-average-color/-/fast-average-color-7.1.0.tgz",
"integrity": "sha512-eTc18sdbr2P2xZFMhvWmo+T7MJ403k4jSiapTMoOcvkptu7SWOU+TzN4tFL4B9sIKUSXA63Xu7Mpc4fmncDZ+Q==",
"dependencies": {
"@types/offscreencanvas": "^2019.6.4"
},
"engines": {
"node": ">= 12"
}
},
"node_modules/fast-copy": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-2.1.1.tgz",
@ -18909,6 +18926,11 @@
}
}
},
"@types/offscreencanvas": {
"version": "2019.6.4",
"resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.6.4.tgz",
"integrity": "sha512-u8SAgdZ8ROtkTF+mfZGOscl0or6BSj9A4g37e6nvxDc+YB/oDut0wHkK2PBBiC2bNR8TS0CPV+1gAk4fNisr1Q=="
},
"@types/parse-json": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
@ -22482,6 +22504,14 @@
"resolved": "https://registry.npmjs.org/extract-files/-/extract-files-9.0.0.tgz",
"integrity": "sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ=="
},
"fast-average-color": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/fast-average-color/-/fast-average-color-7.1.0.tgz",
"integrity": "sha512-eTc18sdbr2P2xZFMhvWmo+T7MJ403k4jSiapTMoOcvkptu7SWOU+TzN4tFL4B9sIKUSXA63Xu7Mpc4fmncDZ+Q==",
"requires": {
"@types/offscreencanvas": "^2019.6.4"
}
},
"fast-copy": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-2.1.1.tgz",

View File

@ -24,6 +24,7 @@
},
"dependencies": {
"buffer": "^6.0.3",
"fast-average-color": "^7.1.0",
"fast-xml-parser": "^4.0.0-beta.8",
"gatsby": "^4.4.0",
"gatsby-plugin-react-svg": "^3.1.0",
@ -38,4 +39,4 @@
"devDependencies": {
"@types/webpack-env": "^1.16.3"
}
}
}

View File

@ -1,16 +1,22 @@
import * as React from "react"
//import useWebSocket from "react-use-websocket";
import { connect } from "mqtt"
import FastAverageColor from 'fast-average-color';
import type { SecretsMQTT, SongInfo } from "../lib/interfaces"
import * as styles from "../styles/containers/Spotify.module.css"
const fac = new FastAverageColor();
const Spotify = ({ mqtt, Alternative }: { mqtt: SecretsMQTT, Alternative: any }) => {
const [lastSongInfo, setLastSongInfo] = React.useState<SongInfo | undefined>(undefined)
const [lastSongInfo, setLastSongInfo] = React.useState<SongInfo>({
playbackState: "STOPPED"
});
const [color, setColors] = React.useState<{bg?: string; text?: string}>({});
const handleMessage = (_topic: string, message: string) => {
try {
const songInfo: SongInfo = JSON.parse(message.toString());
setLastSongInfo(songInfo);
setLastSongInfo((lastInfo) => {return {...lastInfo, ...songInfo}});
} catch {
console.warn(`Can't parse song info: ${message.toString()}`);
}
@ -20,7 +26,7 @@ const Spotify = ({ mqtt, Alternative }: { mqtt: SecretsMQTT, Alternative: any })
const client = connect(mqtt.url, {
username: mqtt.username,
password: mqtt.password,
protocol: "mqtt"
protocol: "ws"
});
client.on("message", handleMessage);
@ -34,12 +40,36 @@ const Spotify = ({ mqtt, Alternative }: { mqtt: SecretsMQTT, Alternative: any })
return () => { client.end() }
}, [])
if (true || !lastSongInfo || lastSongInfo.playbackState !== "PLAYING") {
React.useEffect(() => {
(async () => {
if (lastSongInfo.playbackState !== "STOPPED" && lastSongInfo.cover && lastSongInfo.cover.startsWith("http") && document) {
const { value, isDark } = await fac.getColorAsync(lastSongInfo.cover);
value[3] = 0.8;
setColors({
bg: `rgba(${value.join(",")})`,
text: `var(--textColor${isDark ? "Light" : "Dark"})`
});
} else {
setColors({});
}
})();
}, [lastSongInfo]);
if (lastSongInfo.playbackState === "STOPPED") {
return Alternative;
}
return <div className={`container ${styles.container}`}>
return <div className={`container ${styles.container}`} style={{
background: color.bg,
color: color.text
}}>
{lastSongInfo.cover ? <img src={lastSongInfo.cover} alt="Cover" className={styles.cover} /> : <div></div>}
<div className={styles.meta}>
<span className={styles.title}>{lastSongInfo.title || "Unbekannt"}</span><br/>
<span>{lastSongInfo.artist ? lastSongInfo.artist.join(", ") || "Unbekannt" : "Unbekannt"}</span><br/>
<span>{lastSongInfo.album || "Unbekannt"}</span>
</div>
</div>
}

View File

@ -72,9 +72,10 @@ export interface PlantState {
}
}
export interface SongInfo {
export type SongInfo = {
playbackState: "PLAYING" | "PAUSE" | "STOPPED";
title: string;
artists: string[];
album: string;
title?: string;
artist?: string[];
album?: string;
cover?: string;
}

View File

@ -6,16 +6,31 @@
width:100%;
height:100%;
padding:5px;
background: var(--spotifyColor);
background: var(--containerBg);
border-radius: 5px;
}
.container p {
.meta {
max-width: 21vw;
color: inherit;
word-wrap: normal;
padding: 5px 15px;
height:min-content;
margin: auto 0;
font-size: larger;
}
.meta span:not(:first-child) {
margin-top: 5px;
display: inline-block;
}
.title {
font-size: 180%;
font-size: 170%;
font-weight: bold;
color: inherit;
max-height: calc((19vh - 10px) / 2);
display: inline-block;
overflow-y: hidden;
}
.cover {
height: calc(19vh - 10px);
border-radius: 5px;
}

View File

@ -4,17 +4,22 @@
box-sizing: border-box;
}
:root {
--textColorLight: #b0b0b0;
--textColorDark: #000000;
}
:root, :root[data-theme="day"] {
--containerBg: rgba(255,255,255,0.5);
--textColor: #000000;
color: #000000;
--iconColor: #000000;
--textColor: var(--textColorDark);
color: var(--textColorDark);
--iconColor: var(--textColorDark);
}
:root[data-theme="night"] {
--containerBg: rgba(20,20,20,0.8);
--textColor: #b0b0b0;
color: #b0b0b0;
--iconColor: #b0b0b0;
--textColor: var(--textColorLight);
color: var(--textColorLight);
--iconColor: var(--textColorLight);
}
body, main {