Spotify container
This commit is contained in:
parent
a1300e851d
commit
1e90ecf826
30
package-lock.json
generated
30
package-lock.json
generated
@ -10,6 +10,7 @@
|
|||||||
"license": "GPL-3.0-only",
|
"license": "GPL-3.0-only",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
|
"fast-average-color": "^7.1.0",
|
||||||
"fast-xml-parser": "^4.0.0-beta.8",
|
"fast-xml-parser": "^4.0.0-beta.8",
|
||||||
"gatsby": "^4.4.0",
|
"gatsby": "^4.4.0",
|
||||||
"gatsby-plugin-react-svg": "^3.1.0",
|
"gatsby-plugin-react-svg": "^3.1.0",
|
||||||
@ -2767,6 +2768,11 @@
|
|||||||
"node": ">= 6"
|
"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": {
|
"node_modules/@types/parse-json": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
|
||||||
@ -7475,6 +7481,17 @@
|
|||||||
"url": "https://github.com/sponsors/jaydenseric"
|
"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": {
|
"node_modules/fast-copy": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-2.1.1.tgz",
|
"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": {
|
"@types/parse-json": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/extract-files/-/extract-files-9.0.0.tgz",
|
||||||
"integrity": "sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ=="
|
"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": {
|
"fast-copy": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-2.1.1.tgz",
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
|
"fast-average-color": "^7.1.0",
|
||||||
"fast-xml-parser": "^4.0.0-beta.8",
|
"fast-xml-parser": "^4.0.0-beta.8",
|
||||||
"gatsby": "^4.4.0",
|
"gatsby": "^4.4.0",
|
||||||
"gatsby-plugin-react-svg": "^3.1.0",
|
"gatsby-plugin-react-svg": "^3.1.0",
|
||||||
@ -38,4 +39,4 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/webpack-env": "^1.16.3"
|
"@types/webpack-env": "^1.16.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,22 @@
|
|||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
//import useWebSocket from "react-use-websocket";
|
//import useWebSocket from "react-use-websocket";
|
||||||
import { connect } from "mqtt"
|
import { connect } from "mqtt"
|
||||||
|
import FastAverageColor from 'fast-average-color';
|
||||||
import type { SecretsMQTT, SongInfo } from "../lib/interfaces"
|
import type { SecretsMQTT, SongInfo } from "../lib/interfaces"
|
||||||
import * as styles from "../styles/containers/Spotify.module.css"
|
import * as styles from "../styles/containers/Spotify.module.css"
|
||||||
|
|
||||||
|
const fac = new FastAverageColor();
|
||||||
|
|
||||||
const Spotify = ({ mqtt, Alternative }: { mqtt: SecretsMQTT, Alternative: any }) => {
|
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) => {
|
const handleMessage = (_topic: string, message: string) => {
|
||||||
try {
|
try {
|
||||||
const songInfo: SongInfo = JSON.parse(message.toString());
|
const songInfo: SongInfo = JSON.parse(message.toString());
|
||||||
setLastSongInfo(songInfo);
|
setLastSongInfo((lastInfo) => {return {...lastInfo, ...songInfo}});
|
||||||
} catch {
|
} catch {
|
||||||
console.warn(`Can't parse song info: ${message.toString()}`);
|
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, {
|
const client = connect(mqtt.url, {
|
||||||
username: mqtt.username,
|
username: mqtt.username,
|
||||||
password: mqtt.password,
|
password: mqtt.password,
|
||||||
protocol: "mqtt"
|
protocol: "ws"
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on("message", handleMessage);
|
client.on("message", handleMessage);
|
||||||
@ -34,12 +40,36 @@ const Spotify = ({ mqtt, Alternative }: { mqtt: SecretsMQTT, Alternative: any })
|
|||||||
return () => { client.end() }
|
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 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>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,9 +72,10 @@ export interface PlantState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SongInfo {
|
export type SongInfo = {
|
||||||
playbackState: "PLAYING" | "PAUSE" | "STOPPED";
|
playbackState: "PLAYING" | "PAUSE" | "STOPPED";
|
||||||
title: string;
|
title?: string;
|
||||||
artists: string[];
|
artist?: string[];
|
||||||
album: string;
|
album?: string;
|
||||||
|
cover?: string;
|
||||||
}
|
}
|
@ -6,16 +6,31 @@
|
|||||||
width:100%;
|
width:100%;
|
||||||
height:100%;
|
height:100%;
|
||||||
padding:5px;
|
padding:5px;
|
||||||
background: var(--spotifyColor);
|
background: var(--containerBg);
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
.container p {
|
.meta {
|
||||||
max-width: 21vw;
|
max-width: 21vw;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
word-wrap: normal;
|
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 {
|
.title {
|
||||||
font-size: 180%;
|
font-size: 170%;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
|
max-height: calc((19vh - 10px) / 2);
|
||||||
|
display: inline-block;
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
|
.cover {
|
||||||
|
height: calc(19vh - 10px);
|
||||||
|
border-radius: 5px;
|
||||||
}
|
}
|
@ -4,17 +4,22 @@
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--textColorLight: #b0b0b0;
|
||||||
|
--textColorDark: #000000;
|
||||||
|
}
|
||||||
|
|
||||||
:root, :root[data-theme="day"] {
|
:root, :root[data-theme="day"] {
|
||||||
--containerBg: rgba(255,255,255,0.5);
|
--containerBg: rgba(255,255,255,0.5);
|
||||||
--textColor: #000000;
|
--textColor: var(--textColorDark);
|
||||||
color: #000000;
|
color: var(--textColorDark);
|
||||||
--iconColor: #000000;
|
--iconColor: var(--textColorDark);
|
||||||
}
|
}
|
||||||
:root[data-theme="night"] {
|
:root[data-theme="night"] {
|
||||||
--containerBg: rgba(20,20,20,0.8);
|
--containerBg: rgba(20,20,20,0.8);
|
||||||
--textColor: #b0b0b0;
|
--textColor: var(--textColorLight);
|
||||||
color: #b0b0b0;
|
color: var(--textColorLight);
|
||||||
--iconColor: #b0b0b0;
|
--iconColor: var(--textColorLight);
|
||||||
}
|
}
|
||||||
|
|
||||||
body, main {
|
body, main {
|
||||||
|
Loading…
Reference in New Issue
Block a user