Spotify web player gives Websocket error on raspberry pi - javascript

I am trying to set up spotify player to my raspberry pi. I have codes that work's like a charm on my macbook/chrome but the same codes wont work on raspbian/chromium.
I am getting following errors:
Error while parsing the 'allow' attribute: 'encrypted-media' is an invalid feature name.
{message: "Failed to initialize player"} script.js:44
WebSocket connection to 'wss://gew-dealer.spotify.com/?access_token=removed_my_token'
failed: Error in connection establishment: net:: ERR_NOT_IMPLEMENTED
{message: "Authentication failed"} script.js:45
Here is my script.js:
const hash = window.location.hash
.substring(1)
.split('&')
.reduce(function (initial, item) {
if (item) {
var parts = item.split('=');
initial[parts[0]] = decodeURIComponent(parts[1]);
}
return initial;
}, {});
window.location.hash = '';
// Set token
let _token = hash.access_token;
const authEndpoint = 'https://accounts.spotify.com/authorize';
// Replace with your app's client ID, redirect URI and desired scopes
const clientId = 'removed_my_client_id';
const redirectUri = 'http://localhost:1337';
const scopes = [
'streaming',
'user-read-birthdate',
'user-read-private',
'user-read-email',
'user-modify-playback-state'
];
// If there is no token, redirect to Spotify authorization
if (!_token) {
window.location = `${authEndpoint}?client_id=${clientId}&redirect_uri=${redirectUri}&scope=${scopes.join('%20')}&response_type=token&show_dialog=true`;
}
// Set up the Web Playback SDK
window.onSpotifyPlayerAPIReady = () => {
const player = new Spotify.Player({
name: 'Web Playback SDK Template',
getOAuthToken: cb => { cb(_token); }
});
// Error handling
player.on('initialization_error', e => console.error(e));
player.on('authentication_error', e => console.error(e));
player.on('account_error', e => console.error(e));
player.on('playback_error', e => console.error(e));
// Playback status updates
player.on('player_state_changed', state => {
console.log(state)
$('#current-track').attr('src', state.track_window.current_track.album.images[0].url);
$('#current-track-name').text(state.track_window.current_track.name);
});
// Ready
player.on('ready', data => {
console.log('Ready with Device ID', data.device_id);
// Play a track using our new device ID
play(data.device_id);
});
// Connect to the player!
player.connect();
}
// Play a specified track on the Web Playback SDK's device ID
function play(device_id) {
$.ajax({
url: "https://api.spotify.com/v1/me/player/play?device_id=" + device_id,
type: "PUT",
data: '{"uris": ["spotify:track:5ya2gsaIhTkAuWYEMB0nw5"]}',
beforeSend: function(xhr){xhr.setRequestHeader('Authorization', 'Bearer ' + _token );},
success: function(data) {
console.log(data)
}
});
}
Index.html
<!DOCTYPE html>
<html>
<head>
<title>Spotify Web Playback SDK Template</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://sp-bootstrap.global.ssl.fastly.net/8.0.0/sp-bootstrap.min.css" rel="stylesheet" />
<script
src="https://code.jquery.com/jquery-3.2.1.min.js"
integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
crossorigin="anonymous"></script>
<!-- Include the Web Playback SDK -->
<script src="https://sdk.scdn.co/spotify-player.js"></script>
<!-- Include our Javascript -->
<script src="script.js" defer></script>
</head>
<body class="container">
<h1 class="text-salmon">Spotify Web Playback SDK Template</h1>
<h4>This app uses the implicit grant authorization flow to get an access token and initialise the Web Playback SDK. It then uses the Spotify Connect Web API to play a song.</h4>
<p>If everything is set up properly, you should hear some music!</p>
<img id="current-track"/>
<h3 id="current-track-name"></h3>
<a class="btn btn-salmon btn-lg" href="https://glitch.com/edit/#!/spotify-web-playback">Get started!</a>
</body>
</html>
This code should do:
Initialize the web player
Select one hard coded song
Play the song
Show the image
I have absolutely no idea what could be the problem here. I have been trying a lot of things to fix this but the problem is that i don't know what causes this so i have been just doing stuff without any idea is it going to help. So my question is how i can make this work on raspberry?

Related

Google's JS tutorial for Analytics Reporting API v4 fails due to outdated oauth library

I've set up API access for my (Universal) Analytics project and it works fine from Google's "Demos and Tools" via Request Composer. So then I picked up the simple tutorial HTML file from here:
https://developers.google.com/analytics/devguides/reporting/core/v4/quickstart/web-js
But as soon as the page loads, there's an error in the console saying: You have created a new client application that uses libraries for user authentication or authorization that will soon be deprecated... etc etc.
But the library doesn't seem to have been deprecated yet (this seems to be coming in March 2023).
Anyway, I attempted to keep in pace with the times and use the new library, following the guide here:
https://developers.google.com/identity/gsi/web/guides/migration#popup-mode_1
That led nowhere (403 errors and other problems, as it seems that is not suited for API access). Eventually, though, I found a guide that shows how to use GIS for accessing an API:
https://developers.google.com/identity/oauth2/web/guides/migration-to-gis
Using this, I managed to cobble up together a working query. I'll post it as the answer. This is to help others that are affected by the outdated tutorial.
Enable the Analytics API in the way indicated by this tutorial: https://www.jcchouinard.com/google-api/
You'll want to create credentials for an Internal Web Application, and set "Authorized JavaScript origins" to http://localhost:8080
Save this as .html and serve it on localhost:8080. It should ask you to sign in, you should see the name of your Web Application in the Sign In prompt. And once you press on "Query Reports" you should get a nice JSON back.
<!DOCTYPE html>
<html>
<head>
<script src="https://apis.google.com/js/client:platform.js"></script>
<script src="https://accounts.google.com/gsi/client" onload="initClient()" async defer></script>
</head>
<body>
<script>
var client;
var access_token;
function initClient() {
client = google.accounts.oauth2.initTokenClient({
client_id: 'YOUR-CLIENT-ID',
scope: 'https://www.googleapis.com/auth/analytics.readonly',
callback: (tokenResponse) => {
access_token = tokenResponse.access_token;
},
});
}
function getToken() {
client.requestAccessToken();
}
function revokeToken() {
google.accounts.oauth2.revoke(access_token, () => {console.log('access token revoked')});
}
function loadCalendar() {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://www.googleapis.com/calendar/v3/calendars/primary/events');
xhr.setRequestHeader('Authorization', 'Bearer ' + access_token);
xhr.send();
}
</script>
<script>
// Replace with your view ID.
var VIEW_ID = 'YOUR-VIEW-ID';
// Query the API and print the results to the page.
function queryReports() {
gapi.client.request({
path: '/v4/reports:batchGet',
root: 'https://analyticsreporting.googleapis.com/',
method: 'POST',
body: {
reportRequests: [
{
viewId: VIEW_ID,
dateRanges: [
{
startDate: '7daysAgo',
endDate: 'today'
}
],
metrics: [
{
expression: 'ga:sessions'
}
]
}
]
}
}).then(displayResults, console.error.bind(console));
}
function displayResults(response) {
var formattedJson = JSON.stringify(response.result, null, 2);
document.getElementById('query-output').value = formattedJson;
}
</script>
<h1>Google Identity Services Authorization Token model</h1>
<button onclick="getToken();">Get access token</button><br><br>
<button onclick="queryReports();">Query Reports</button><br><br>
<button onclick="revokeToken();">Revoke token</button>
<!-- The API response will be printed here. -->
<textarea cols="80" rows="20" id="query-output"></textarea>
</body>
</html>

injection - How user can pay custom value of ETH with metamask API?

I want to give user possibility to choose his own value of Ether. How to do this?
How efficiently change the network when pressing connect to metamask (for example when user will press this button metamask should change network to binance smart chain (ID 56)
here is my code:
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/web3#latest/dist/web3.min.js"></script>
</head>
<body>
<div>
<button class="enableEthereumButton btn">Enable Ethereum</button>
<button class="sendEthButton btn">Send Eth</button>
<div id="status"></div>
</div>
<script type="text/javascript">
// Running on the page, in the browser
if (typeof window.ethereum !== 'undefined') {
console.log('MetaMask is installed!');
}
if (!ethereum || !ethereum.isMetaMask) {
throw new Error('Please install MetaMask.')
}
/*********************************************************/
/* Handle chain (network) and chainChanged, per EIP 1193 */
/*********************************************************/
// Do this:
ethereum.on('chainChanged', (chainId) => {
/* handle the chainId */
});
const ethereumButton = document.querySelector('.enableEthereumButton');
const sendEthButton = document.querySelector('.sendEthButton');
let accounts = [];
//Sending Ethereum to an address
sendEthButton.addEventListener('click', () => {
ethereum
.request({
method: 'eth_sendTransaction',
params: [
{
from: accounts[0],
to: '0x6adress.................',
value: '0x00',
gasPrice: '0x0000001F6EA08600',
gas: '0x0001ADB0',
},
],
})
.then((txHash) => console.log(txHash))
.catch((error) => console.error);
});
ethereumButton.addEventListener('click', () => {
getAccount();
});
async function getAccount() {
accounts = await ethereum.request({ method: 'eth_requestAccounts' });
}
</script>
</body>
</html>
Metamask screenshot
Add an input field for the value and pass it in to your params. This is basic html form + javascript interactions, not specific to web3, so for more info on how to do that I would look here https://www.w3schools.com/html/html_forms.asp
To read the network the user is connecting with in your app you can listen for a chain change event: https://docs.metamask.io/guide/ethereum-provider.html#events
Then if they are not connected to a network your app supports you should show the user a notice.

Picking random image from array 60+ choices javascript

I understand this question has tons of answers already, but I am trying to figure out how to do this in the most efficient way. I have a website that sends an image with a button click to a phone number, but I want to choose between 60 or so photos and manually entering all of these image locations into an array does not seem ideal.
Here is my js file that performs the email action, this is all hosted on a free hosting service.
// server.js
const express = require("express")
const app = express()
app.use(express.static("public"))
app.get("/", (req, res) => {
res.sendFile(__dirname + "/index.html")
/* this sends the "index.html" file when people go to app.glitch.me/ */
})
app.get("/send", (req, res) => {
// where node app starts
var nodemailer = require('nodemailer');
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: process.env.USER,
pass: process.env.PASS,
}
});
var mailOptions = {
from: process.env.USER,
to: process.env.RECIP,
subject: "As you requested",
text: '',
attachments: [
{
/*image location*/
path: 'https://post.healthline.com/wp-content/uploads/sites/3/2020/02/322868_1100-1100x628.jpg',
}
]
};
transporter.sendMail(mailOptions, function(error, info){
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});
res.redirect("/sent.html") // after sending the email, redirect back to "index.html" at app.glitch.me/
})
app.listen(3000); //open for traffic
Here is my HTMl if its even relevant to my question
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hello!</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- import the webpage's stylesheet -->
<link rel="stylesheet" href="/style_index.css">
click me for snazzy pics<!-- script to ping --!>
<!-- import the webpage's javascript file -->
<script src="/script.js" defer></script>
</head>
<body>
<h1>hello</h1>
<p>
I made this.
</p>
</body>
</html>
Try first logging all of your images from where they are hosted. If it is not a database you can call upon then you may need to create an array of them manually. Once they are in an object, you can simply use a variable to determine which position in the array that image link should come from. I hope the below helps.
For example:
imageChoices = ["https://post.healthline.com/wp-content/uploads/sites/3/2020/02/322868_1100-1100x628.jpg", "https://post.healthline.com/wp-content/uploads/sites/3/2020/02/322868_1100-1100x628.jpg", etc.]
randomIndexChooser = Math.floor(Math.random() * 60) + 1;
var mailOptions = {
from: process.env.USER,
to: process.env.RECIP,
subject: "As you requested",
text: '',
attachments: [
{
/*image location*/
path: imageChoices[randomIndexChooser],
}
]
};
you need to make an ajax service that calls an api, the api loops through all the files that are in the specified folder and returns the list of file paths. after you get the list from the api, you append them to the wanted array in your javascript code.
I will provide you a sample in asp.net c# , you may be working on another framework, but you can benefit from the idea at least.
here is a function in an api
[HttpGet]
public List<string> GetImageFilesPaths()
{
//getfiles returns all found files' paths in a specified directory
List<string> imageFilePaths = Directory.GetFiles("folderpath", "*.png", SearchOption.AllDirectories).ToList();
}
ajax service that calls the API
$.ajax({
url:'hostname/apiname/GetImageFilesPaths'
contentType: "application/json",
dataType: 'json',
success: function(result){
//here you append the result which is the list of file path
//into your wanted array, you can also loop
result.forEach((imagePath)=>{
arrayOfImages.push(imagePath)
})
}
})

twitter api - nodejs problems

i am fairly new to NodeJS and the twitter api and I encountered some problems. Disclaimer: Because the terms of usage for the twitter api are strict i want to make clear that i am not going to profit anything off this project and i am not going to harm anyone's privacy using it.
So i have this html page:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="bot.css" type="text/css">
<title>document</title>
</head>
<body>
<div class="main">
<h1></h1>
</div>
<script src="bot.js"></script>
<script src="config.js"></script>
</body>
</html>
config.js :
module.exports = {
consumer_key: '',
consumer_secret: '',
access_token: '',
access_token_secret: '',
timeout_ms: 60*1000, // optional HTTP request timeout to apply to all requests.
strictSSL: true, // optional - requires SSL certificates to be valid.
}
and the bot.js :
var Twit=require('twit');
var config=require('./config');
var T = new Twit(config);
let params = {
q: 'polar-bear since:2011-07-11',
count: 2
}
function getData(err, data, response){
for(let i=0;i<data.statuses.length;i++){
console.log(`Tweet number ${i+1} : ${data.statuses[i].text}`);
}
}
T.get('search/tweets', params, getData)
let page=document.querySelector('h1');
when i run only the bot.js file in terminal it works fine however
when i run the code on the web console i get 2 Reference
ReferenceError: Can't find variable: require ...
ReferenceError: Can't find variable: module

Progressive Web App and caching UI

I'm developing a PWA with all functionalities (as offline, add to home screen, notification,..) but I have some problem when I try to refresh the UI.
In other words, I have my PWA with the UI defined in the index.html file, the thing that I want to do is caching the PWA for use it offline (and I'm able to do this) and if the device is online check if there are some update of UI (in index.html file, or in the file which it depends), download this changes and refresh the UI on the device and inside the cache.
With the data I haven't any problem with the cache.
For example if I have this page index.html:
<!DOCTYPE html>
<html>
<head >
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title class="title">PWA</title>
<link rel="manifest" href="manifest.json">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="PWA">
<link rel="apple-touch-icon" href="imgs/icons/Icon-152.png">
<meta name="msapplication-TileImage" content="imgs/icons/Icon-144.png">
<meta name="msapplication-TileColor" content="#2F3BA2">
<link rel="shortcut icon" sizes="32x32" href="imgs/icons/Icon-32.png">
<link rel="shortcut icon" sizes="196x196" href="imgs/icons/Icon-196.png">
<link rel="apple-touch-icon-precomposed" href="imgs/icons/Icon-152.png">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-12">
<img src="imgs/images.png">
</div>
</div>
</div>
<script src="js/jquery.js"></script>
<script src="js/bootstrap.js"></script>
<script src="js/app.js"></script>
</body>
</html>
app.js:
if('serviceWorker' in navigator) {
navigator.serviceWorker
.register('service-worker.js')
.then(function() { console.log('Service Worker Registered'); });
}
service-worker.js:
var dataCacheName = 'dataCache-v2';
var cacheName = 'cache-v2';
var filesToCache = [
'index.html',
'imgs/images.png',
'src/app.js'
];
self.addEventListener('install', function(e) {
console.log('[ServiceWorker] Install');
e.waitUntil(
caches.open(cacheName).then(function(cache) {
console.log('[ServiceWorker] Caching App Shell');
return cache.addAll(filesToCache);
})
);
});
self.addEventListener('activate', function(e) {
console.log('[ServiceWorker] Activate');
e.waitUntil(
caches.keys().then(function(keyList) {
return Promise.all(keyList.map(function(key) {
console.log('[ServiceWorker] Removing old cache', key);
if (key !== cacheName && key !== dataCacheName) {
return caches.delete(key);
}
}));
})
);
return self.clients.claim();
});
self.addEventListener('fetch', function(e) {
console.log('[ServiceWorker] Fetch', e.request.url);
var dataUrl = 'URL-WHERE-FIND-DATA';
if (e.request.url.indexOf(dataUrl) === 0) {
e.respondWith(
fetch(e.request)
.then(function(response) {
return caches.open(dataCacheName).then(function(cache) {
cache.put(e.request.url, response.clone());
console.log('[ServiceWorker] Fetched&Cached Data');
return response;
});
})
);
} else {
e.respondWith(
caches.match(e.request).then(function(response) {
return response || fetch(e.request);
})
);
}
});
Suppose that I replace the images.png with another image but with the same name, how can I show the new one to the user?
If I refresh the page the data is get from the network (if it is avaiable) but the image still catch from the cache.
I hope that I have explained my problem well. Thanks a lot to everyone that will help me
UPDATE #1:
I tried to implements the "Cache then network" strategy as Arnelle Balane suggested to me, but the problem is always here, the browser show always the cached images (in the code below I try to update an image called 'demo.jpg').
Probably I'm doing something wrong.
This is my code:
service-worker.js:
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.open("my-cache").then(function(cache) {
return fetch(event.request).then(function(response) {
console.log('Fetch: ' + response.url);
cache.put(event.request, response.clone());
return response;
});
})
);
});
app.js:
var networkDataReceived = false;
var networkUpdate = fetch('https://website.com/app/images/demo.jpg').then(function(response) {
return response.blob();
}).then(function(data) {
networkDataReceived = true;
updatePage(data);
});
caches.match('https://website.com/app/images/demo.jpg').then(function(response) {
if (!response) throw Error("No data");
return response.blob();
}).then(function(data) {
if (!networkDataReceived) {
updatePage(data);
}
}).catch(function() {
return networkUpdate;
}).catch(showErrorMessage);
function showErrorMessage(response){
console.log("Error: " + response);
}
function updatePage(response) {
var img = document.getElementById('demo');
var imageUrl = URL.createObjectURL(response);
img.src = imageUrl;
}
Any new suggestions? Thanks
UPDATE #2:
Now I’m trying to do everything from the beginning.
I have copy the service worker from this google’s example: https://developers.google.com/web/fundamentals/getting-started/codelabs/your-first-pwapp/
That implements the "Cache then network" strategy.
The code of service-worker.js is this:
var dataCacheName = 'dataCache1';
var cacheName = 'cache1';
var filesToCache = [
'/',
'index.html',
'css/main.css',
'src/app.js'
];
self.addEventListener('install', function(e) {
console.log('[ServiceWorker] Install');
e.waitUntil(
caches.open(cacheName).then(function(cache) {
console.log('[ServiceWorker] Caching app shell');
return cache.addAll(filesToCache);
})
);
});
self.addEventListener('activate', function(e) {
console.log('[ServiceWorker] Activate');
e.waitUntil(
caches.keys().then(function(keyList) {
return Promise.all(keyList.map(function(key) {
if (key !== cacheName && key !== dataCacheName) {
console.log('[ServiceWorker] Removing old cache', key);
return caches.delete(key);
}
}));
})
);
/*
* Fixes a corner case in which the app wasn't returning the latest data.
* You can reproduce the corner case by commenting out the line below and
* then doing the following steps: 1) load app for first time so that the
* initial New York City data is shown 2) press the refresh button on the
* app 3) go offline 4) reload the app. You expect to see the newer NYC
* data, but you actually see the initial data. This happens because the
* service worker is not yet activated. The code below essentially lets
* you activate the service worker faster.
*/
return self.clients.claim();
});
self.addEventListener('fetch', function(e) {
console.log('[Service Worker] Fetch', e.request.url);
var dataUrl = 'https:/mywebsite.it/service/images/demo.jpg';
if (e.request.url.indexOf(dataUrl) > -1) {
/*
* When the request URL contains dataUrl, the app is asking for fresh
* weather data. In this case, the service worker always goes to the
* network and then caches the response. This is called the "Cache then
* network" strategy:
* https://jakearchibald.com/2014/offline-cookbook/#cache-then-network
*/
e.respondWith(
caches.open(dataCacheName).then(function(cache) {
return fetch(e.request).then(function(response){
cache.put(e.request.url, response.clone());
return response;
});
})
);
} else {
/*
* The app is asking for app shell files. In this scenario the app uses the
* "Cache, falling back to the network" offline strategy:
* https://jakearchibald.com/2014/offline-cookbook/#cache-falling-back-to-network
*/
e.respondWith(
caches.match(e.request).then(function(response) {
return response || fetch(e.request);
})
);
}
});
And the result is always the same, the image won’t to get update.
With the fetch(url) method, the service worker should get the image from the network, right?
The result of the code is shown in the image below.
When I reload the page the only fetched request is the folder “/service/”
If I try to “force” the loading of the image that I want to update with an explicit request to browser (https://mywebsite.com/service/images/demo.jpg) the service worker correclty fetch the request but shown always the old image.
I think that I’m doing something foolishly wrong but I not understand what.
The reason why the image is being served from the cache is because that's what the service worker is coded to do:
e.respondWith(
caches.match(e.request).then(function(response) {
return response || fetch(e.request);
})
);
This checks your cache first if a response for the request is already stored, and only fetches the resource from the network if not.
As I see it, you have two possible ways of dealing with that:
Make sure that the file names of the resources (including images) change when the actual content of that resource changes. There are several build tools out there that can do this for you by appending the resource's hash to its file name. A change in the resource's contents will result into a different hash, and thus a different file name.
You can use the Cache then network strategy as described in this article by Jake Archibald. The idea is that you serve the cached resource if it is available, while at the same time you request for that resource over the network. Once the network request completes, you replace the previously-served content with the one you got from the network, as well as update the cached version of the resource. This way, you can be sure that the user is seeing the latest version of a resource, while still not breaking the offline experience by having an updated cached version of that resource.

Categories