I am trying to get the duration of a youtube video via search
var request = gapi.client.youtube.search.list({
q: q,
type : "video",
maxResults : 10,
part: 'snippet,contentDetails'
});
as an additional part parameter I added contentDetails in order to get the duration as you can see in their doc.
https://developers.google.com/youtube/v3/getting-started
Now comes the silly part. The response I get is the following:
[
{
"error": {
"code": -32602,
"message": "contentDetails",
"data": [
{
"domain": "youtube.part",
"reason": "unknownPart",
"message": "contentDetails",
"locationType": "parameter",
"location": "part"
}
]
},
"id": "gapiRpc"
}
]
"As such, the part parameter requires you to select the resource components that your application actually uses"
Thats what I did and now they dont know their own parameter anylonger?
So I was wondering how can I retrieve the duration order contentDetails in general?
best
phil
As written in the document, for search->list call, part can only take value "snippet".
Depending on the kind of the response, as a secondary call, you can do one of videos->list, playlists->list, channels->list with the id and part=snippet,contentDetails to get more details of each result item.
Related
When I click I a link (or am getting redirected by a site), I want to replace the values of assorted tracking parameters in the requested URL with a different, universal value. For this example, let's use my username, so a link that directs to
www.abc.com/?utm_source=originalsource&utm_campaign=originalcampaign&cid=originalcid&gclid=originalgclid
would become www.abc.com/?utm_source=WTTDOTM&utm_campaign=WTTDOTMcampaign&cid=WTTDOTM&gclid=WTTDOTM
It’s important that these parameters get edited before the request is sent off, as the idea is to avoid the UTM/cid/gclid/etc tracking and leave a mark in the traffic data of whoever is looking at those tracking parameters. I know I have to use webRequest, and the logic seems pretty simple, but I don’t know how to find-and-replace in the URL on the fly with js. This answer looks like its the closest to what I’m asking, but I don’t know how it would work with just modifying smaller slices of a URL as I'm pretty inexperienced with javascript and most of my coding knowledge is just slapping stuff together until it works.
To start with a simple sub-problem my question is: how can I use the webRequest API to replace utm_campaign=*** in a URL with utm_campaign=WTTDOTM before the page is requested?
----EDIT:-----
#wOxxOm thank you for your helpful answer! I think I have the general structure down now, but I am still struggling with the formatting of regex rules, which I'm pretty unfamiliar with. The way I understand it, the rule ^(.*?utm_source=)(.+?(?=\\&)|$)(.*) (and its "medium" variant) will capture all values before 'utm_source=' into group 1 and all values (or none in the case of it being the last parameter) after '&' into group 3 and then I should be able to make the regexSubstition group1+WTTDOTM+group3, right? When I currently try to upload the unpacked extension below, I get hit with an error that says "rules.json: Rule with id 1 specifies an incorrect value for the "regexFilter" key." I think I am just formatting it wrong, but I do not know what I need to fix. Can you help? Here are my rules.json and manifest.json files.
rules.json
[
{
"id": 1,
"priority": 1,
"action": {
"type": "redirect",
"redirect": {
"regexSubstitution": "\\1WTTDOTM\\3"
}
},
"condition": {
"regexFilter": "^(.*?utm_source=)(.+?(?=\\&)|$)(.*)",
"resourceTypes": [
"main_frame"
]
}
},
{
"id": 2,
"priority": 2,
"action": {
"type": "redirect",
"redirect": {
"regexSubstitution": "\\1WTTDOTM\\3"
}
},
"condition": {
"regexFilter": "^(.*?utm_medium=)(.+?(?=\\&)|$)(.*)",
"resourceTypes": [
"main_frame"
]
}
}
]
manifest.json
{
"manifest_version": 2,
"name": "WTTDOTM is a UTM",
"version": "1.3",
"permissions": [
"declarativeNetRequest",
"declarativeNetRequestFeedback",
"<all_urls>"
],
"description": "Replaces all UTM values with 'WTTDOTM'",
"declarative_net_request" : {
"rule_resources" : [{
"id": "1",
"enabled": true,
"path": "rules.json"
},
{
"id": "2",
"enabled": true,
"path": "rules.json"
}],
"icons": {
"128": "icon128.png" }
}
}
It's probably not impossible to do this with regular expressions but it's going to be frustrating. The text that you're trying to capture could contain almost anything, so building a regex that captures what's after each query parameter and only what's after each query parameter is going to be difficult. Instead I would suggest using Chrome's built in URLSearchParams API.
Combined with Javascript's URL object, what you're trying to do would probably look like this:
const replaceTrackerParams = (urlString, replacementString) => {
const url = new URL(urlString);
const params = new URLSearchParams(url.search);
// If campagin parameters exist, replace them
params.has('utm_source') && params.set('utm_source', replacementString)
params.has('utm_campaign') && params.set('utm_campaign', replacementString)
// Return modified URL
return url.hostname + '?' + params.toString()
}
Replace shorthand syntax with more complicated logic as needed.
Another answer suggested using declarativeNetRequest because it is the newer, more efficient API. This is true, but I don't think it supports callback functions yet.
When I was browsing Google YouTube DATA API and I found object gapi.client.youtube.commentThreads.insert, I tried to use it but I didn't know how to use it and Data API documentation doesn't tell much about it, insted of this Google uses buildApiRequest function to create request.
I tried to write and run code like this above, but it returns error 400
Code:
var c = new gapi.client.youtube.commentThreads.insert(
{
"part":"snippet"
},{
'snippet.channelId': 'UC_x5XG1OV2P6uZZ5FSM9Ttw',
'snippet.videoId':'NeF0zpT4gNE',
'snippet.topLevelComment.snippet.textOriginal':'Hello from API'
});
c.execute();
Response
{
"error": {
"errors": [
{
"domain": "youtube.commentThread",
"reason": "channelOrVideoIdMissing",
"message": "Each comment thread must be linked to a channel or video.\u003cul\u003e\u003cli\u003eIf the comment applies to a channel, make sure that the resource specified in the request body provides a value for the \u003ccode\u003e\u003ca href=\"/youtube/v3/docs/commentThreads#snippet.channelId\"\u003esnippet.channelId\u003c/a\u003e\u003c/code\u003e property. A comment that applies to a channel appears on the channels \u003cb\u003eDiscussion\u003c/b\u003e tab.\u003c/li\u003e\u003cli\u003eIf the comment applies to a video, make sure the resource specifies values for both the \u003ccode\u003e\u003ca href=\"/youtube/v3/docs/commentThreads#snippet.channelId\"\u003esnippet.channelId\u003c/a\u003e\u003c/code\u003e and \u003ccode\u003e\u003ca href=\"/youtube/v3/docs/commentThreads#snippet.videoId\"\u003esnippet.videoId\u003c/a\u003e\u003c/code\u003e properties. A comment that applies to a video appears on the videos watch page.\u003c/li\u003e\u003c/ul\u003e",
"locationType": "other",
"location": "body.snippet"
}
],
"code": 400,
"message": "Each comment thread must be linked to a channel or video.\u003cul\u003e\u003cli\u003eIf the comment applies to a channel, make sure that the resource specified in the request body provides a value for the \u003ccode\u003e\u003ca href=\"/youtube/v3/docs/commentThreads#snippet.channelId\"\u003esnippet.channelId\u003c/a\u003e\u003c/code\u003e property. A comment that applies to a channel appears on the channels \u003cb\u003eDiscussion\u003c/b\u003e tab.\u003c/li\u003e\u003cli\u003eIf the comment applies to a video, make sure the resource specifies values for both the \u003ccode\u003e\u003ca href=\"/youtube/v3/docs/commentThreads#snippet.channelId\"\u003esnippet.channelId\u003c/a\u003e\u003c/code\u003e and \u003ccode\u003e\u003ca href=\"/youtube/v3/docs/commentThreads#snippet.videoId\"\u003esnippet.videoId\u003c/a\u003e\u003c/code\u003e properties. A comment that applies to a video appears on the videos watch page.\u003c/li\u003e\u003c/ul\u003e"
}
}
I found solution, I was stupid because parameters must be passed by object - here is example for someone who would use this function.
var c = new gapi.client.youtube.commentThreads.insert(
{
"part": "snippet"
},
{
"snippet": {
"channelId": "UC_x5XG1OV2P6uZZ5FSM9Ttw",
"videoId": "NeF0zpT4gNE",
"topLevelComment": {
"snippet": {
"textOriginal": "Hello from API"
}
}
}
}
);
c.execute();
I have a slack app implemented in node.js where I am dynamically displaying a drop-down menu from an Options Load URL to a channel on the Slack group.
The drop down is getting displayed correctly based on the options JSON that I am returning form the external URL,
but now the problem is that I need to have separate items in the drop-down menu based on what the user has entered on the slack channel.
For example:
If the user says: give me choices for option 1: then the value 1 should be passed to the Options Load URL and the code that I have implemented at that URL will reply with the appropriate JSON based on the input value 1.
Next, when the User says give me choices for option 2: then the value 2 should be passed to the Options Load URL and the code implemented there will reply the options based on the value 2 that it receives.
The code at the Options Load URL is already implemented. The code for extracting the number 1 or 2 from the user message is also implemented.
The values 1 or 2 ... etc. are not constant or fixed. These can by random and the API at Options Load URL will be able to correctly handle these values.
I just need to figure out a way to send these values to the Options Load URL somehow.
Is it possible to do this somehow in Slack?
Use the name property in your request to pass a custom value to the part of your app that handles the options requests from Slack ("Options Load URL"). I use it usually to select which predefined options list to return, but you can also use it to dynamically create a new option list based on the value.
For reference here is the example Slack request for creating a dynamic menu (from the offical documentation), where you can see the name property under action. In this example it has the value "bugs_list":
{
"text": "What's bugging you?",
"response_type": "in_channel",
"attachments": [
{
"fallback": "Upgrade your Slack client to use messages like these.",
"color": "3AA3E3",
"attachment_type": "default",
"callback_id": "select_remote_1234",
"actions": [
{
"name": "bugs_list",
"text": "Which random bug do you want to resolve?",
"type": "select",
"data_source": "external",
"min_query_length": 3,
}
]
}
]
}
And here is what your Options Load URL will receive. Notice the name parameter.
{
"name": "bugs_list",
"value": "bot",
"callback_id": "select_remote_1234",
"team": {
"id": "T012AB0A1",
"domain": "pocket-calculator"
},
"channel": {
"id": "C012AB3CD",
"name": "general"
},
"user": {
"id": "U012A1BCJ",
"name": "bugcatcher"
},
"action_ts": "1481670445.010908",
"message_ts": "1481670439.000007",
"attachment_id": "1",
"token": "verification_token_string"
}
The name parameter is a common parameter in a HTTP request, so you can put pretty much everything in there, even data structures, as long as they are encoded as strings. Also see my other answer that talks about the limits of passing data in Slack parameters.
I'm struggling to 'munge' my JSON into the correct format.
To illustrate i've made a quick, JSfiddle.
http://jsfiddle.net/chrismasters/NQKvy/638/
The format the server returns the data has a couple of differences to the preferred format recommended by Ember Data now.
Here is the raw JSON output
{
"video": {
"uuid": "8a660002-03c6-4b8e-bd8b-4ce28fa0dacd",
"state": "pending",
"theme": "basic",
"resolution": "nHD",
"title": "Test title",
"track": {
"uuid": "376fc3bb-d703-49e7-9d92-bce7f6bf8b56",
"state": "complete",
"source": "upload"
}
}
}
The first is that rather than use IDs it uses a UUID that is a string.
I seem to have managed to fix that using the normalizeHash, for video at least - but i'm not sure whether the same approach will fix the track model too - especially if I use embedding as I need to.
This is where the big problems start to appear, if I comment out the belongsTo relationship from the video model then it works OK, so I think... it is clearly a problem with the JSON formatting for the embedded track data.
Here are the model definitions and the serialization
App.Video = DS.Model.extend({
title: DS.attr('string'),
//track: DS.belongsTo('track', { embedded: true })
});
App.VideoSerializer = DS.RESTSerializer.extend({
normalizeHash: {
video: function(hash) {
hash.id = hash.uuid;
delete hash.uuid;
return hash;
}
}
});
I'd really appreciate some advice on how to format this response into a format that Ember Data recognises.
Also - does anyone know of a tool or good way of debugging these serialization transformations because at the moment the error message from Ember is not very helpful in terms of debugging or seeing what the serialization output is.
Many thanks for any help you can suggest.
Chris
In case anyone else has the same confusion over serializations I thought i'd include an explanation how to solve this problem.
Here is the working jsbin:
http://jsbin.com/fuzu/4
The main points are:
Primary Keys
primaryKey: 'uuid'
Is useful to convert the id into the correct naming & needs to be applied explicitly to any serializers (using globally on a ApplicationSerializer didn't seem to work).
Model Relationships
track: DS.belongsTo('track', {embedded: true} )
Ensure the definition of the relationship includes embedding & only on one side.
Extract Single
extractSingle: function(store, type, payload, id, requestType) {
var tracks = [];
var track = payload.video.track;
var video = payload.video;
tracks.push(track);
video.track = payload.video.track.uuid;
payload = { video: video, track: tracks };
return this._super(store, type, payload, id, requestType);
}
Pluralization is really important for Ember Data to understand the relationships, even though the model relationship is a belongsTo.
You can see this clearly in the desired (working) JSON
{
"video": {
"id": "8a660002-03c6-4b8e-bd8b-4ce28fa0dacd",
"state": "pending",
"theme": "basic",
"resolution": "nHD",
"title": "Test title",
"track": "2"
},
"track": [{
"id": "2",
"state": "complete",
"source": "upload"
}]
}
The track value in video isn't wrapped in an array, yet the root track value is an array.
For this reason I found it very useful first define the desired JSON and test it working first, then try to munge the real JSON into that format.
I think a tool to help with this process (visualising real-time JSON output from seraliziation) could be a great addition to Ember Data & something I'm going to look into creating.
I'm still trying to write a function in JavaScript where the user can type in an artist, and it will return a link to that artist's SoundCloud page.
For example,
/artist beyonce --> https://soundcloud.com/beyoncemusic
But the SoundCloud URLS don't all act the same. For example,
/artist dave matthews band --> https://soundcloud.com/dave-matthews-band.
For this reason, I can't simply just output scLink/artistName because they all have different URLs. I'm using Node.js, so I looked through a lot of npm packages, but couldn't figure out how to use any for this purpose. Perhaps Soundclouder will work somehow (though I couldn't figure it out myself). Does anyone know how I could write a command like this?
You are using the SoundCloud API, right?
A simple HTTP request to the right API should return the data you want. For example:
http://api.soundcloud.com/users.json?q=beyonce
[
{
"id": 4293843,
"kind": "user",
"permalink": "beyoncemusic",
"username": "Beyoncé",
"uri": "http://api.soundcloud.com/users/4293843",
"permalink_url": "http://soundcloud.com/beyoncemusic",
"avatar_url": "http://i1.sndcdn.com/avatars-000036935308-a2acxy-large.jpg?435a760",
"country": "United States",
"full_name": "Beyoncé",
"description": "",
"city": "New York",
"discogs_name": null,
"myspace_name": "beyonce",
"website": "http://www.beyonceonline.com",
"website_title": "",
"online": false,
"track_count": 33,
"playlist_count": 2,
"plan": "Pro Plus",
"public_favorites_count": 0,
"followers_count": 478783,
"followings_count": 0,
"subscriptions": [
{
"product": {
"id": "creator-pro-unlimited",
"name": "Pro Unlimited"
}
}
]
},
...
]
...so you could just do results[0].permalink_url.
You can use the request module to make the HTTP request manually, or use soundclouder to handle SoundCloud API's authentication details.
Most of the above does not apply if you want to make the actual requests from a browser. (The question is tagged node.js, but it sounds like you want to do this from a web page.)
If you're doing this from a webpage, use the SoundCloud JS SDK. The data you get back will look like the example above.
I don't think you'd be able to get an exact match reliably. Your best bet would be to search for users with the string you are looking for - example: "beyonce" and then to show the results and let them pick the correct link. You may be able to filter out likely results with follower count (high follower count) or something after you've pulled the initial list from soundcloud.
Search code:
users = SC.get('/users', { q: 'beyonce' });
Then iterate over users and display the permalink url. Hope this helps.