Skip to content

Commit d5f4532

Browse files
authored
Merge pull request #75 from Fabrizz/dev-features
Dev features
2 parents 77af57c + a42808e commit d5f4532

7 files changed

Lines changed: 71 additions & 19 deletions

File tree

MMM-OnSpotify.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ Module.register("MMM-OnSpotify", {
9999
ONSPOTIFY_HIDE: "ONSPOTIFY_HIDE",
100100
},
101101

102-
// Allow config with or without
102+
// Allow config with or without subdivition
103103
isPlaying: 1,
104104
isEmpty: 2,
105105
isPlayingHidden: 1,
@@ -135,10 +135,15 @@ Module.register("MMM-OnSpotify", {
135135
experimentalCanvasEffect: "cover",
136136
// Add the album cover inside the canvas
137137
experimentalCanvasAlbumOverlay: true,
138+
experimentalCanvasSPDCookie: "",
138139

139140
// In special use cases where a frontend needs to take over other you can disabl
140141
// the id matching for the frontend, so "multiple" frontends can talk to the module even if not supported
141142
matchBackendUUID: false,
143+
144+
// Send a notification with the color data when only when the song changes, this is useful for modules
145+
// that are not going to show the color inside the dom.
146+
experimentalColorSignaling: false,
142147
},
143148

144149
start: function () {
@@ -199,6 +204,8 @@ Module.register("MMM-OnSpotify", {
199204
version: this.version,
200205
},
201206
(a, b) => this.translate(a, b),
207+
(a, b) => this.sendNotification(a, b), // This is not the best as I would like this logic to be separated from the,
208+
// DomBuilder but I dont have time to refractor everything. Solves #81 issue
202209
);
203210

204211
/* Future update:
@@ -685,13 +692,14 @@ Module.register("MMM-OnSpotify", {
685692
userAffinityUseTracks: this.config.userAffinityUseTracks,
686693
deviceFilter: this.config.deviceFilter,
687694
deviceFilterExclude: this.config.deviceFilterExclude,
688-
useCanvas: this.config.experimentalCanvas
695+
useCanvas: this.config.experimentalCanvas,
689696
},
690697
credentials: {
691698
clientId: this.config.clientID,
692699
clientSecret: this.config.clientSecret,
693700
accessToken: this.config.accessToken,
694701
refreshToken: this.config.refreshToken,
702+
experimentalCanvasSPDCookie: this.config.experimentalCanvasSPDCookie,
695703
},
696704
language: this.config.language,
697705
backendExpectId: this.backendExpectId,

README.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ The module includes an Authentication Service that guide you through the configu
99
> [!NOTE]
1010
> All the data stays in your mirror. If you have multiple mirrors, the Authentication Service guides you on creating a new Spotify App per mirror.
1111
12-
1312
https://github.com/Fabrizz/MMM-OnSpotify/assets/65259076/5d78672e-8feb-45de-92f4-ed44f0771432
1413

1514
https://github.com/Fabrizz/MMM-OnSpotify/assets/65259076/f7c0928f-3806-48ba-a813-87962dd9ea8b
1615

16+
> This module shows what is on your Spotify Connect. if you want to use Spotify in your mirror you should look at [Raspotify](https://github.com/dtcooper/raspotify)
1717
1818
# Installation
1919
### Step 1: Clone the module and install dependencies
@@ -91,6 +91,7 @@ Once you finish, you are all set with the basic configuration. Scroll down to se
9191
experimentalCanvas: false,
9292
experimentalCanvasEffect: 'cover',
9393
experimentalCanvasAlbumOverlay: false,
94+
experimentalCanvasSPDCookie: "",
9495
// Theming General
9596
roundMediaCorners: true,
9697
roundProgressBar: true,
@@ -103,6 +104,7 @@ Once you finish, you are all set with the basic configuration. Scroll down to se
103104
blurCorrectionInAllSides: false,
104105
alwaysUseDefaultDeviceIcon: false,
105106
experimentalCSSOverridesForMM2: false, // [SEE BELOW]
107+
experimentalColorSignaling: false,
106108
},
107109
},
108110
```
@@ -177,11 +179,18 @@ experimentalCSSOverridesForMM2: [
177179
| spotifyCodeExperimentalSeparateItem <br> `true` | Separates or joins the Spotify Code Bar to the cover art. Also respects `roundMediaCorners` and `spotifyCodeExperimentalUseColor`. <br /><br /><img alt="Spotify code bar separation" src=".github/content/readme/banner-codeseparation.png" aling="left" height="100"> |
178180

179181
#### Canvas
182+
> [!IMPORTANT]
183+
> EXPERIMENTAL - Using this without auth will get this funtion rate-limited. For that you can add a `experimentalCanvasSPDCookie`. This is more advanced as it requieres you to get the cookie from a Spotify Web session. Not recommended for all users.
184+
185+
> [!CAUTION]
186+
> Canvases are an internal implementation by the Spotify team and its not available in the web API. Use at your own discretion, personal usage only.
187+
180188
| Key | Description |
181189
| :-- | :-- |
182190
| experimentalCanvas <br> `false` | Shows the Spotify Canvas if available. This is an experimental feature, as this API is not documented and private. |
183-
| experimentalCanvasEffect <br> `cover` | Control how is the canvas is going to be displayed. Options are: <br />- `cover`: The Canvas is clipped to have the same height as the album cover. Recommended for low-power devices and if the module is not in a `bottom_*` position. <br />- `scale`: Scale up/down the module to fit the entire Canvas without clipping it. <br /> |
184191
| experimentalCanvasAlbumOverlay <br> `true` | Show the cover art inside the Spotify Canvas. |
192+
| experimentalCanvasEffect <br> `cover` | Control how is the canvas is going to be displayed. Options are: <br />- `cover`: The Canvas is clipped to have the same height as the album cover. Recommended for low-power devices and if the module is not in a `bottom_*` position. <br />- `scale`: Scale up/down the module to fit the entire Canvas without clipping it. <br /> |
193+
| experimentalCanvasSPDCookie <br> `""` | Adds the SPD cookie from a web Spotify session to stop Spotify from returning a 500 error. Spotify could decide also to just send a 500 error depending on the user agents and other factors, this just affects the module. Still, this feature is optional and this API is NOT public. You can search "Extract Spotify SPD cookie" in youtube/other to learn how to do this. **DO NOT** share this cookie!. |
185194

186195
#### General Theming options
187196
| Key | Description |
@@ -197,6 +206,7 @@ experimentalCSSOverridesForMM2: [
197206
| blurCorrectionInAllSides <br> `false` | Same as `blurCorrectionInFrameSide`, but applies the correction on all of the borders for a more subtle effect. |
198207
| alwaysUseDefaultDeviceIcon <br> `false` | The device icon changes depending on the player type. If you don’t like this behaviour you can disable it. |
199208
| experimentalCSSOverridesForMM2 <br> `false` | An array containing CSS overrides, OnSpotify manages the status depending on what is displayed on the screen and lets you customize other modules. [See above](#theming-3rd-party-modules) |
209+
| experimentalColorSignaling <br> `false` | Sends a notification with the color data for modules that are not DOM based and need the color when its already processed. |
200210

201211
> See also: [Disabling **all** color based theming](#other)
202212
@@ -223,6 +233,7 @@ Control your mirror (and other modules) using Apple Homekit protocol! (Also comp
223233
| key | Description |
224234
| :-- | :-- |
225235
| `THEME_PREFERENCE` | ↑ Sent to signal other modules that color data is available. |
236+
| `INSTANT_COLOR` | ↑ Sent to signal other modules that color data has been updated instantly, also sends the raw vibrant data, only when `experimentalColorSignaling` is turned on. |
226237
| `NOW_PLAYING` | ↑ When the player state changes, the module sends a notification so other modules can, for example, [show lyrics](#lyrics). |
227238
| `DEVICE_CHANGE` | ↑ Everytime the Spotify Connect target changes, this notification is fired. |
228239
| `ONSPOTIFY_NOTICE` | ↑ This notification signals other modules that OnSpotify is available. |
@@ -267,5 +278,7 @@ You cannot migrate from NowPlayingInSpotify, as the scopes included in the NPOS
267278

268279
- Contributions wanted! Add features or your language using `translations/yourLanguage.json`. Currently we have translations for: Spanish, English, German
269280

281+
- You can custom CSS and functions in the "Issues" tab. For example https://github.com/Fabrizz/MMM-OnSpotify/issues/65 for changing the size and hiding other modules using ONSP state.
282+
270283
With <3 by Fabrizio | [fabriz.co](https://fabriz.co/) | Star this repository!
271284
[<img alt="Fabrizz logo" src=".github/content/readme/logo-fabrizz-fill.png" width="200" align="right">](https://fabriz.co/)

auth/client/index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,8 @@ <h4 class="card-header py-3">Step 3: Configure your mirror</h4>
242242
clientID: <span style="color: rgb(242, 210, 152);">"{{clientID}}"</span>,
243243
clientSecret: <span style="color: rgb(242, 210, 152);">"{{clientSecret}}"</span>,
244244
accessToken: <span style="color: rgb(242, 210, 152);">"{{accessToken}}"</span>,
245-
refreshToken: <span style="color: rgb(242, 210, 152);">"{{refreshToken}}"</span>
246-
<span style="color: rgba(255, 255, 255, 0.48);">/* Add here your theming and behaviour configurations */</span>
245+
refreshToken: <span style="color: rgb(242, 210, 152);">"{{refreshToken}}"</span>,
246+
<span style="color: rgba(255, 255, 255, 0.48);">/* Add here your configurations */</span>
247247
}
248248
},</pre>
249249

node_helper.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ module.exports = NodeHelper.create({
295295
try {
296296
// use then to prevent context issue
297297
this.fetcher.getCanvas(uri).then(canvas => {
298-
console.log("[CANVAS DATA]", JSON.stringify(canvas), typeof x)
298+
// console.log("[CANVAS DATA]", JSON.stringify(canvas))
299299

300300
if (canvas.canvasesList.length == 1 && canvas.canvasesList[0].canvasUrl.endsWith('.mp4')) {
301301
const item = canvas.canvasesList[0];

utils/SpotifyDomBuilder.js

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@
88
/* eslint-disable no-undef */
99

1010
class SpotifyDomBuilder {
11-
constructor(pathPrefix, config, other, translator) {
11+
constructor(pathPrefix, config, other, translator, externalNotifier) {
1212
this.pathPrefix = pathPrefix;
1313
this.config = { ...config, ...other };
1414
this.translate = translator;
15+
this.notifyModules = externalNotifier;
1516
this.root = document.querySelector(":root");
1617
this.firstUpdate = true;
1718
this.lastItemURI = null;
@@ -610,7 +611,6 @@ class SpotifyDomBuilder {
610611
}
611612

612613
updateCanvas(data) {
613-
console.log("SYNC", data)
614614
const container = document.getElementById("VSNO-TARGET-SWAPPABLE");
615615
this.coverData = data;
616616
if (container == null) return;
@@ -767,12 +767,10 @@ class SpotifyDomBuilder {
767767

768768
/* Image color processing */
769769
async setGlobalColors(url, data) {
770-
const ch = url !== this.lastUrlProcessed ? "" : "[PALETTE CACHED] | ";
770+
const shouldUpdatePalette = url !== this.lastUrlProcessed;
771+
771772
this.firstUpdate = false;
772-
const palette =
773-
url !== this.lastUrlProcessed
774-
? await this.getVibrant(url)
775-
: this.lastPalette;
773+
const palette = shouldUpdatePalette ? await this.getVibrant(url) : this.lastPalette;
776774

777775
if (!palette) return;
778776
this.lastPalette = palette;
@@ -785,6 +783,16 @@ class SpotifyDomBuilder {
785783
);
786784
}
787785

786+
// Notify external modules about the color change instantly after the color is set
787+
// Added to fix/help #81
788+
if (this.config.experimentalColorSignaling)
789+
this.notifyModules("INSTANT_COLOR", {
790+
vibrantRawOutput: palette,
791+
isCacheedPalette: !shouldUpdatePalette,
792+
forUrl: url,
793+
})
794+
795+
788796
// Fix color data using RGB_Linear_Shade to get more contrast
789797
// This is used in the SpotifyCode bar, if enabled with useColorInProgressBar
790798
// its also used there for continuity
@@ -873,7 +881,7 @@ class SpotifyDomBuilder {
873881
(Brightness_By_Color(palette.Vibrant.hex) / 255) * 100,
874882
)}%`
875883
: ""
876-
} | ${ch}${data.itemName} | ${url}`,
884+
} | ${shouldUpdatePalette ? "" : "[PALETTE CACHED] | "}${data.itemName} | ${url}`,
877885
`padding:0.7em;border-radius:3em;background-color:${palette.Vibrant.hex}`,
878886
`padding:0.7em;border-radius:3em;margin-left:0.3em;background-color:${palette.LightVibrant.hex};color:${palette.DarkVibrant.hex}`,
879887
`padding:0.7em;border-radius:3em;margin-left:0.3em;background-color:${palette.DarkVibrant.hex};color:${palette.LightVibrant.hex}`,

utils/SpotifyFetcher.js

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,14 @@ module.exports = class SpotifyFetcher {
201201
"\x1b[0m[\x1b[35mMMM-OnSpotify\x1b[0m] Refresh access token >> \x1b[41m\x1b[37m CODE 429 \x1b[0m %s",
202202
"You are being rate limited by Spotify (429). Use only one SpotifyApp per module/implementation",
203203
);
204+
if (res.status !== 200) {
205+
console.warn(
206+
`\x1b[0m[\x1b[35mMMM-OnSpotify\x1b[0m] Refresh access token >> \x1b[41m\x1b[37m CODE ${res.status} \x1b[0m %s`,
207+
"Error refreshing access token. Check your credentials, account type or status.",
208+
);
209+
return new Error("Error refreshing access token")
210+
}
211+
204212
return res.json();
205213
})
206214
.catch((error) => {
@@ -239,7 +247,7 @@ module.exports = class SpotifyFetcher {
239247
'accept': 'application/protobuf',
240248
'content-type': 'application/x-www-form-urlencoded',
241249
'accept-language': 'en',
242-
'user-agent': 'Spotify/8.5.49 iOS/Version 13.3.1 (Build 17D50)',
250+
'user-agent': 'Spotify/8.6.98 iOS/15.3.1',
243251
'accept-encoding': 'gzip, deflate, br',
244252
'authorization': `Bearer ${this.canvasToken}`,
245253
},
@@ -270,7 +278,23 @@ module.exports = class SpotifyFetcher {
270278
if (currentTime < this.canvasTokenExpiresAt) {
271279
return this.canvasToken
272280
} else {
273-
return fetch(new URL("get_access_token?reason=transport&productType=web_player", spotifyBase))
281+
let ccc = {
282+
headers: {
283+
//"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/114.0",
284+
//Accept:
285+
// "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
286+
//"Accept-Language": "en-US,en;q=0.5",
287+
//"Alt-Used": "open.spotify.com",
288+
//"Upgrade-Insecure-Requests": "1",
289+
//"Sec-Fetch-Dest": "document",
290+
//"Sec-Fetch-Mode": "navigate",
291+
//"Sec-Fetch-Site": "cross-site",
292+
}
293+
}
294+
if (this.credentials.experimentalCanvasSPDCookie.length > 0) {
295+
ccc.headers.Cookie = `sp_dc=${this.credentials.experimentalCanvasSPDCookie}`;
296+
}
297+
return fetch(new URL("get_access_token?reason=transport&productType=web_player", spotifyBase), ccc)
274298
.then(async res => {
275299
if (!res.ok && res.status === 429)
276300
console.warn(

utils/canvas/readme.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
## Experimental canvas implementation
22
Original:
3-
* https://github.com/Vibrant-Colors/node-vibrant
4-
3+
* https://github.com/bartleyg/my-spotify-canvas
54
Implementation:
65
* https://github.com/dientuki
76
* https://github.com/Fabrizz/MMM-OnSpotify/issues/66

0 commit comments

Comments
 (0)