Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Canva update #74

Merged
merged 21 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add canvas in a ugly way
  • Loading branch information
dientuki committed Apr 30, 2024
commit 8595d44391ae47f32761a7b83d4dec04b386a84c
8 changes: 8 additions & 0 deletions MMM-OnSpotify.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ Module.register("MMM-OnSpotify", {
this.userData = null;
this.playerData = null;
this.affinityData = null;
this.canvasData = null;
// this.queueData = null;
// this.recentData = null;

Expand Down Expand Up @@ -443,6 +444,10 @@ Module.register("MMM-OnSpotify", {
this.sendNotification("SERVERSIDE_RESTART");
this.sendCredentialsBackend();
break;
case "CANVAS":
this.canvasData = payload;
this.smartUpdate("CANVAS");
break
}
},
notificationReceived: function (notification, payload) {
Expand Down Expand Up @@ -658,6 +663,9 @@ Module.register("MMM-OnSpotify", {
if (type === "USER_DATA") this.builder.updateUserData(this.userData);
if (type === "AFFINITY_DATA")
this.builder.updateAffinityData(this.affinityData);
if (type === "CANVAS") {
this.builder.updateCanvasData(this.canvasData);
}
},

getImage: (im, prefersLarge) =>
Expand Down
14 changes: 14 additions & 0 deletions node_helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ module.exports = NodeHelper.create({
// Use a identifier to filter socket-io retries.
this.appendableId = undefined;
this.serversideId = Date.now().toString(16);
this.currentTrack = null;
},

socketNotificationReceived: function (notification, payload) {
Expand Down Expand Up @@ -132,6 +133,19 @@ module.exports = NodeHelper.create({
// CASE 1 The data is OK and there is an ITEM in the player
let isTrack =
data.currently_playing_type === "track" ? true : false;

if (this.currentTrack != data.item.id) {
this.currentTrack = data.item.id;

let canvas = await this.fetcher.getCanvas(data.item.uri);
let mp4 = null;
if (canvas.canvasesList.length == 1) {
console.log(canvas.canvasesList[0].canvasUrl);
mp4 = canvas.canvasesList[0].canvasUrl.endsWith('.mp4') ? canvas.canvasesList[0].canvasUrl : null;
}
this.sendSocketNotification("CANVAS", mp4);
}

let payload = {
/* Player data */
playerIsPlaying: data.is_playing,
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@
"homepage": "https://github.com/Fabrizz/MMM-OnSpotify#readme",
"license": "MIT",
"dependencies": {
"axios": "^1.6.8",
"body-parser": "^1.20.1",
"cookie-parser": "^1.4.6",
"dompurify": "^3.0.6",
"express": "^4.18.2",
"google-protobuf": "^3.21.2",
"node-fetch": "^2.6.9",
"querystring": "^0.2.1",
"request": "^2.88.2"
Expand Down
21 changes: 21 additions & 0 deletions utils/SpotifyDomBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,21 @@ class SpotifyDomBuilder {
if (this.config.theming.spotifyCodeExperimentalShow) {
player.appendChild(this.getSpotifyCodeDom(data.itemUri));
}
const mycanvas = document.createElement("div");
mycanvas.classList.add("mycanvas");

const video = document.createElement('video');
video.id = "VSNO-TARGET-VIDEO";
video.type = 'video/mp4'
video.muted = true;
video.controls = false;
video.autobuffer = true;
video.autoplay = true;
video.loop = true;
mycanvas.appendChild(video);

player.appendChild(mycanvas);

player.appendChild(footer);
return player;
}
Expand Down Expand Up @@ -465,6 +480,12 @@ class SpotifyDomBuilder {
this.setSpotifyCode(u, "VSNO-TARGET-CODE", true);
return experimental;
}

updateCanvasData(data) {
const vid = document.getElementById("VSNO-TARGET-VIDEO");
vid.src = data != null ? data : '';
}

updatePlayerData(data) {
if (!document.getElementById("ONSP-WRAPPER")) return;
if (
Expand Down
59 changes: 59 additions & 0 deletions utils/SpotifyFetcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@

// Use node fetch as most MM2 installs use older node
const fetch = require("node-fetch");
const axios = require('axios');
const tokenRefreshBase = "https://accounts.spotify.com";
const userBase = "https://api.spotify.com";
const openSpotify = "https://open.spotify.com/";
const canvasesUrl = 'https://spclient.wg.spotify.com/canvaz-cache/v0/canvases';
const canvas = require('./canvas_pb.js');

module.exports = class SpotifyFetcher {
constructor(payload) {
Expand Down Expand Up @@ -39,6 +43,41 @@ module.exports = class SpotifyFetcher {
}
}

async getCanvas(trackUri) {
let canvasRequest = new canvas.CanvasRequest();
const canvasToken = await this.getCanvasToken();

let spotifyTrack = new canvas.CanvasRequest.Track();
spotifyTrack.setTrackUri(trackUri);
canvasRequest.addTracks(spotifyTrack);
let requestBytes = canvasRequest.serializeBinary();

const options = {
responseType: 'arraybuffer',
headers: {
'accept': 'application/protobuf',
'content-type': 'application/x-www-form-urlencoded',
'accept-language': 'en',
'user-agent': 'Spotify/8.5.49 iOS/Version 13.3.1 (Build 17D50)',
'accept-encoding': 'gzip, deflate, br',
'authorization': `Bearer ${canvasToken.accessToken}`,
}
}
return axios.post(canvasesUrl, requestBytes, options)
.then(response => {
if (response.statusText !== 'OK') {
console.log(`ERROR ${canvasesUrl}: ${response.status} ${response.statusText}`);
if (response.data.error) {
console.log(response.data.error);
}
} else {
return canvas.CanvasResponse.deserializeBinary(response.data).toObject();
}
})
.catch(error => console.log(`ERROR ${canvasesUrl}: ${error}`));

}

formatTime(milliseconds) {
const formattedTime = new Date(milliseconds).toLocaleTimeString("en-US", {
hour12: false,
Expand Down Expand Up @@ -182,6 +221,26 @@ module.exports = class SpotifyFetcher {
}
}

getCanvasToken() {

return fetch(new URL("get_access_token?reason=transport&productType=web_player", openSpotify))
.then(res => {
if (!res.ok && res.status === 429)
console.warn(
"\x1b[0m[\x1b[35mMMM-OnSpotify\x1b[0m] Refresh access token >> \x1b[41m\x1b[37m CODE 429 \x1b[0m %s",
"You are being rate limited by Spotify (429). Use only one SpotifyApp per module/implementation",
);
return res.json();
})
.catch((error) => {
console.error(
"\x1b[0m[\x1b[35mMMM-OnSpotify\x1b[0m] getCanvasToken >> \x1b[41m\x1b[37m Request error \x1b[0m",
error,
);
return error;
});
}

refreshAccessToken() {
let client_id = this.credentials.clientId;
let client_secret = this.credentials.clientSecret;
Expand Down
28 changes: 28 additions & 0 deletions utils/canvas.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// generate javascript interfaces:
// $ protoc --proto_path=api --js_out=import_style=commonjs,binary:api/ api/_canvas.proto

syntax = "proto3";

message CanvasRequest {
message Track {
string track_uri = 1; // spotify:track:5osCClSjGplWagDsJmyivf
}
repeated Track tracks = 1;
}

message CanvasResponse {
message Canvas {
string id = 1; // ef3bc2ac86ba4a39b2cddff19dca884a
string canvas_url = 2; // https://canvaz.scdn.co/upload/artist/6i1GVNJCyyssRwXmnaeEFH/video/ef3bc2ac86ba4a39b2cddff19dca884a.cnvs.mp4
string track_uri = 5; // spotify:track:5osCClSjGplWagDsJmyivf
message Artist {
string artist_uri = 1; // spotify:artist:3E61SnNA9oqKP7hI0K3vZv
string artist_name = 2; // CALVO
string artist_img_url = 3; // https://i.scdn.co/image/2d7b0ebe1e06c74f5c6b9a2384d746673051241d
}
Artist artist = 6;
string other_id = 9; // 957a9be5e5c1b9ef1ac1c96b7cebf396
string canvas_uri = 11; // spotify:canvas:1OuybAWK7XOQMG725ZtFwG
}
repeated Canvas canvases = 1;
}
Loading