possible spotify portrait metadata caching bug - spotify

Code to replicateIn my app I have the following code.
var seed = "spotify:artist:3UbyYnvNIT5DFXU4WgiGpP";
sp.core.getMetadata(seed, {
onSuccess: function (metadata) {
console.log(metadata);
},
onFailure: function () {}
});
Steps to view the behaviour
If spotify is already open close it and then reopen it, after opening spotify run the app and view the console Which displays as
Object
name: "Whitesnake"
portrait: ""
type: "artist"
uri: "spotify:artist:3UbyYnvNIT5DFXU4WgiGpP"
__proto__: Object
Then click on the radio app and create a station based on the the band Whitesnake.
Rerun the original app and view the console output which will display.
Object
name: "Whitesnake"
portrait: "spotify:image:3c4aa30d845dd456d750cf16bef8e2cadb2af342"
type: "artist"
uri: "spotify:artist:3UbyYnvNIT5DFXU4WgiGpP"
__proto__: Object
Quit spotify and rerun the original application and view the console which will display
Object
name: "Whitesnake"
portrait: ""
type: "artist"
uri: "spotify:artist:3UbyYnvNIT5DFXU4WgiGpP"
__proto__: Object
Question
Why is the radio app able to access a portrait uri that is then accessible from my app after using the radio app? Is there some sort of initialization, that needs to be done first or is this a bug?

Some information on an artist (and album, etc) isn't available until you do a "browse" on that URI - until then, Spotify only downloads basic information on an item to keep performance up.
What you're seeing is the Radio doing a browse, which causes the Spotify client to fill in the missing information.
An update to Spotify is coming soon that will improve this behaviour.

If I understood you correctly, you've noticed that after you get the result with a portrait URI from the radio, you get that object data populated when using it in your app?
On another note; you should be using the Artist class instead of sp.core.
var sp = getSpotifyApi(1);
var models = sp.require('sp://import/scripts/api/models');
models.Artist.fromURI("spotify:artist:3UbyYnvNIT5DFXU4WgiGpP", function(album) {
console.log(album);
});
This should give you the correct output with a portrait uri string.
Artist
data: Object
name: "Whitesnake"
portrait: "spotify:image:3c4aa30d845dd456d750cf16bef8e2cadb2af342"
type: "artist"
uri: "spotify:artist:3UbyYnvNIT5DFXU4WgiGpP"

As iKenndac mentioned, try doing a 'browse':
var seed = "spotify:artist:3UbyYnvNIT5DFXU4WgiGpP";
sp.core.browseUri(seed, {
onSuccess: function (metadata) {
console.log(metadata);
},
onFailure: function () {}
});
Examples here: https://github.com/ptrwtts/kitchensink

Related

Can't figure out how to upload file and json in form data react

I'm building a MERN stack web app and I want the users to be able to upload post with an image and post data.
The data looks like this:
title: 'The war in Ukraine continues',
text: 'Volodymyr Horbenko is the latest official to lose his job after Mr Zelensky said bosses failed to root out pro-Russian elements in the agency',
sources: [
'https://www.bbc.com/news/world-62223264',
'https://www.theguardian.com/world/live/2022/jul/19/russia-ukraine-war-live-news-putin-and-erdogan-to-meet-us-weaponry-stabilising-frontlines-ukraine-military-chief-says',
],
locations: [
{
description: 'boutcha',
type: 'Point',
coordinates: [-122.479887, 38.510312],
},
{
description: 'kyiv',
type: 'Point',
coordinates: [-122.582948, 38.585707],
},
],
};
now I also want to upload a picture this is just a photo that comes from an input.
I know that I should use formData to send the picture and i've tried uploading the data as well like this:
const form = new FormData();
form.append('data', JSON.stringify(data));
form.append('imageCover', fileInputRef.current.files[0]);
axios.post('/api/v1/stories/', form);
but when it comes to the backend I haven't been able to figure out how to retrieve the data into the request body. I've tried using multer app.use(multer.single('data'));(which works fine for the pictures) and app.use(express.json({ type: 'multipart/form-data' }));
but I get Error: Unexpected end of form, and Error:Unexpected token - in JSON at position 0 errors respectively.
also, if there is another way of sending both form data and files i'd like to hear about it, keep in mind that because there are nested objects I can't simply write form.append(key,value) for each pair in the data
app.post("/api/v1/stories", multer().single("imageCover"), function(req, res) {
var file = req.file;
var data = JSON.parse(req.body.data);
});

Hubspot API - list of properties needed (nodejs)

I am integrating the hubspot API to track user interaction with our site. I am creating dynamic lists and I want to filter a user into a certain contact list by which URL they visit.
"filters": [
[
{
"operator": "CONTAINS",
"property": "hs_URL",
"value": `${id}`
},
],
]
I keep getting this error for all my attempts:
{"status":"error","message":"Couldn't find a Property with the given name 'hs_URL'","correlationId":"0723dcee-534b-4f92-9104-509d6885abbe","propertiesErrorCode":"PROPERTY_NOT_FOUND"},
I cannot seem to find a master property list and have tried many string combinations. Anyone familiar with hubspot property lists would be my savior.
Thank you~!
It's been a few months, so you may not need this anymore, but since I landed here while looking for a way to get all the properties from an object type in hubspot using nodejs, this might help others looking for the solution.
The master list of properties can be retrieved with the following API call:
const response = await hubspotClient.crm.properties.coreApi.getAll(objectType, false);
The arguments for getAll() expect:
objectType: a string, i.e "contacts".
archived: a boolean, i.e false. Set this true if you want to get archived properties.
The following code was adapted based on this page from the hubspot API docs:
https://developers.hubspot.com/docs/api/crm/properties
Once you're on the page, you can click on the "Endpoints" Tab to reveal code snippets for multiple environments, including nodejs.
For this example, getProperties(), retrieves all properties for a given object type. I used contacts for the object type, which I believe is where you are storing the url property, but you could use the same function to get properties for other object types such as companies or deals.
It might be worth noting that I mapped the results to return just the property names, which sounds like all you need for your case, but more information is contained in the results if you need it. Just remove this bit to get more information on each property:
.map(prop => prop.name)
const hubspot = require('#hubspot/api-client')
const hubspotClient = new hubspot.Client({ apiKey: "YOUR_API_KEY" })
const getProperties = async (objectType) => {
try {
const response = await hubspotClient.crm.properties.coreApi.getAll(objectType, false);
return response.body.results.map(prop => prop.name);
} catch (e) {
e.message === 'HTTP request failed'
? console.error(JSON.stringify(e.response, null, 2))
: console.error(e);
}
}
Here's an example for running the function to get a list of all property names for contacts.
(async () => {
var properties = await getProperties("contacts");
console.log(JSON.stringify(properties ,null,2));
})();
It took me a bit to find this, so figured I would post here in the hopes it saves time for someone else. This is the first time I've posted a solution, and I'm pretty new to this API and Hubspot in general, so feedback and/or better solutions are welcome. Cheers.

LoopBack Remote Methods and Access to Model Data

I've been working on this for hours and I'm completely lost, because the loopback documentation is not helpful.
I'm trying to write application logic into a model. The documentation for that is here. Unfortunately, the example doesn't demonstrate anything useful other than passing an external value into the remote method and returning it again. I'd like to understand how to run a query in this context and access model data, but I have searched for hours and not been able to find documentation on even these simple tasks. Maybe I'm just looking in the wrong places. Can anyone help?
Typically, you can accomplish most things you'd want to do such as querying and accessing model data (CRUD operations) through the built-in methods that all models get; see http://docs.strongloop.com/display/LB/Working+with+data. Defining a remote method (custom REST endpoint) for these would be redundant.
You access the standard model CRUD Node APIs (e.g. myModel.create(), myModel.find(), myModel.updateAll() ) in the remote method code if you want to.
You may also find further related examples in https://github.com/strongloop/loopback-example-app-logic
Here's an example using the Getting Started app https://github.com/strongloop/loopback-getting-started app. It defines a remote method that takes a number arg and prints the name of the coffeeshop with that ID to the console:
This code is in common/models/coffeeshop.js:
module.exports = function(CoffeeShop) {
...
// Return Coffee Shop name given an ID.
CoffeeShop.getName = function(shopId, cb) {
CoffeeShop.findById( shopId, function (err, instance) {
response = "Name of coffee shop is " + instance.name;
cb(null, response);
console.log(response);
});
}
...
CoffeeShop.remoteMethod (
'getName',
{
http: {path: '/getname', verb: 'get'},
accepts: {arg: 'id', type: 'number', http: { source: 'query' } },
returns: {arg: 'name', type: 'string'}
}
);
};
You can use the API Explorer to load http://0.0.0.0:3000/explorer/#!/CoffeeShops/getName then enter a number (there are only three coffee shops in the app initially) as the query param and hit "Try It Out!"
Or just GET a URL like http://0.0.0.0:3000/api/CoffeeShops/getid?id=1
Rand
I finally discovered my problem. Object properties must be loaded in a callback of the function calling the CRUD operation. The following syntax worked for me:
module.exports = function (TestModel) {
TestModel.testRemoteMethod = function (id, name, cb) {
TestModel.findOne({where: {id: id}}, function(err, modelInstance) {
//modelInstance has properties here and can be returned to
//the API call using the callback, for example:
cb(null, {"name": modelInstance.name});
}
}
TestModel.remoteMethod('testRemoteMethod',
//..rest of config

Hoodie - Update a CouchDB document (Node.js)

I'm handling charges and customers' subscriptions with Stripe, and I want to use these handlings as a Hoodie plugin.
Payments and customer's registrations and subscriptions appear normally in Stripe Dashboard, but what I want to do is update my _users database in CouchDB, to make sure customer's information are saved somewhere.
What I want to do is updating the stripeCustomerId field in org.couchdb.user:user/bill document, from my _users database which creates when logging with Hoodie. And if it is possible, to create this field if it does not exist.
In hoodie-plugin's document, the update function seems pretty ambiguous to me.
// update a document in db
db.update(type, id, changed_attrs, callback)
I assume that type is the one which is mentioned in CouchDB's document, or the one we specify when we add a document with db.add(type, attrs, callback) for example.
id seems to be the doc id in couchdb. In my case it is org.couchdb.user:user/bill. But I'm not sure that it is this id I'm supposed to pass in my update function.
I assume that changed_attrs is a Javascript object with updated or new attributes in it, but here again I have my doubts.
So I tried this in my worker.js:
function handleCustomersCreate(originDb, task) {
var customer = {
card: task.card
};
if (task.plan) {
customer.plan = task.plan;
}
stripe.customers.create(customer, function(error, response) {
var db = hoodie.database(originDb);
var o = {
id: 'bill',
stripeCustomerId: 'updatedId'
};
hoodie.database('_users').update('user', 'bill', o, function(error) {
console.log('Error when updating');
addPaymentCallback(error, originDb, task);
});
db.add('customers.create', {
id: task.id,
stripeType: 'customers.create',
response: response,
}, function(error) {
addPaymentCallback(error, originDb, task);
});
});
}
And between other messages, I got this error log:
TypeError: Converting circular structure to JSON
And my file is not updated : stripeCustomerId field stays null.
I tried to JSON.stringify my o object, but It doesn't change a thing.
I hope than some of you is better informed than I am on this db.update function.
Finally, I decided to join the Hoodie official IRC channel, and they solved my problem quickly.
Actually user.docs need an extra API, and to update them you have to use hoodie.account instead of hoodie.database(name)
The full syntax is:
hoodie.account.update('user', user.id, changedAttrs, callback)
where user.id is actually the account name set in Hoodie sign-up form, and changedAttrs an actual JS object as I thought.
Kudos to gr2m for the fix; ;)

Do I have two instances of the same store?

i populate a listview using a store with jsonp proxy that sends a GET request to my server. when the app launches the request is send and the list items are rendered with the response as they should. now when i then manually add a new item in my data-base server and refresh the list with the code shown in the controller below and inspect the store object in the console i can see that the newly created item is in the store data. so far so good, everything as expected. however, the new item is not in the refreshed in the list. the strange thing is that when i inspect the list object and its containing store object the newly created item is not included. However when i relaunch the app (rather than reload the store and refresh the list) new newly created item appears in the list. to me it seems that somehow i have 2 store instances, one with the new data (which i retreive with Ext.getStore) and one without (the one inside the listview) which i thought should be actually the same. how is that possible? below i show you how i do the thing. Any help is greatly appreciated.
the controller
Ext.define('VB1.controller.ListController', {
extend: 'Ext.app.Controller',
config: {
refs: {
listView: 'listview',
refreshButtonTap: '#refreshbutton',
},
control: {
refreshButtonTap: {
onRefreshList: 'refreshList',
},
}
},
launch: function () {
this.callParent(arguments);
Ext.getStore('MyStore').addListener('load', 'recordLoaded', this);
},
refreshList: function () {
var loadedStore = Ext.getStore('MyStore').load();
console.log(loadedStore) //here the new item is included
},
recordLoaded: function () {
var list = this.getListView();
list.refresh();
console.log(list) //here the new item is not included in the store object inside
//listobject
}
});
the Store
Ext.define('VB1.store.MyStore', {
extend: 'Ext.data.Store',
alias: 'widget.mystore',
config: {
model: 'VB1.model.MyModel',
autoLoad: true,
proxy: {
type: 'jsonp',
url : 'myUrl.js',
enablePagingParams: false,
reader: {
type: 'json',
rootProperty: 'array.resources'
},
},
},
});
the listview
Ext.define('VB1.view.ListView', {
extend: 'Ext.dataview.List',
alias: 'widget.listview',
requires: [
'Ext.dataview.List',
],
scrollable: 'vertical',
config: {
loadingText: "loading...",
emptyText: '</pre><div class="notes-list-empty-text">No notes found.</div><pre>',
itemTpl: '</pre><div class="list-item-title">{title}</div><div class="list-item-narrative"><img src="{listlogo}"/></div><pre>',
},
listeners: {
itemtap: function(list, index, item, record) {
this.fireEvent('showDetails', record, this);
}
},
});
this is how i add the list including the store to the viewport at app launch
var listView = {
xtype: 'listview',
store: {xtype: 'mystore'},
}
Ext.Viewport.add(listView);
I just found out what the problem was. first of all the store was instantiated 2 times as I suspected. obviously one time by the app and another time by the view. hence i ended up with having two stores. since i did not set a storeID the stores became identified by two unique ids based on the xtype name i have given in the alias config of the store.
the store i resolved and logged in the controller like below had the id ex-mystore-1
var loadedStore = Ext.getStore('MyStore').load();
console.log(loadedStore) //here the new item was included
and the store inside the list view object got the id ext-mystore-2
var list = this.getListView();
console.log(list._store); //here the new item was not included
what changed the hole problem in my favor was when i added a storeId to the store. after that i still had two stores, however, with the same storeIds (but with with different unique or observable ids). the good new was that now the new item was included in both store instances. i also was able to get rid of the second store instance by not instantiating the xtype of the store in the listview but reference it by storeID. Now everything works as it should. thanks to anybody who looked at this. i hope this helpes somebody who finds similar trouble.

Resources