Get all videos of a YouTube Playlist in Java - java

Context I'm working with Android Studio (Java). I want to obtain all the videos of a given playlist (or 50, I will get all the other after).
Problem I see people using url like
https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&playlistId=PLiEwZfNgb4fVrRzTonlVEMj6DB2Nmzg2M&key=AIzaSyC2_YRcTE9916fsmA0_KRnef43GbLzz8m0
but I don't know how to implement this in Java. I follow some tuto and I got a way to get information totally different like :
YouTube.Search.List query;
query = youtube.search().list("id,snippet");
query.setKey(MY_API_KEY);
query.setMaxResults((long)20);
query.setType("video");
query.setFields("items(id/videoId,snippet/title,snippet/description,snippet/thumbnails/default/url)");
And I really don't understand how do I get something else than a search.
Most of documentation is in english only...
EDIT
Ok, so I continued to try, I think I got a near solution, but I got an error.
private YouTube youtube;
private YouTube.PlaylistItems.List playlistItemRequest;
private String PLAYLIST_ID = "PLiEwZfNgb4fVrRzTonlVEMj6DB2Nmzg2M";
public static final String KEY = "AIzaSyC2_YRcTE9916fsmA0_KRnef43GbLzz8m0";
// Constructor
public YoutubeConnector(Context context)
{
youtube = new YouTube.Builder(new NetHttpTransport(),
new JacksonFactory(), new HttpRequestInitializer()
{
#Override
public void initialize(HttpRequest hr) throws IOException {}
}).setApplicationName(context.getString(R.string.app_name)).build();
}
public List<VideoItem> result()
{
List<PlaylistItem> playlistItemList = new ArrayList<PlaylistItem>();
try
{
/* HERE MUST BE MY PROBLEM ! */
playlistItemRequest = youtube.playlistItems().list("snippet");
playlistItemRequest.setPlaylistId(PLAYLIST_ID);
playlistItemRequest.setFields("items(id/videoId,snippet/title,snippet/description,snippet/thumbnails/default/url),nextPageToken,pageInfo");
playlistItemRequest.setKey(KEY);
String nextToken = "";
do {
playlistItemRequest.setPageToken(nextToken);
PlaylistItemListResponse playlistItemResult = playlistItemRequest.execute();
playlistItemList.addAll(playlistItemResult.getItems());
nextToken = playlistItemResult.getNextPageToken();
} while (nextToken != null);
}catch(IOException e)
{
Log.d("YC", "Could not initialize: "+e);
}
//[...]
}
Here is the error I got :
{
"code" : 400,
"errors" : [ {
"domain" : "global",
"location" : "fields",
"locationType" : "parameter",
"message" : "Invalid field selection videoId",
"reason" : "invalidParameter"
} ],
"message" : "Invalid field selection videoId"
}
EDIT 2 Thanks to : Martijn Woudstra.
Correct line was :
playlistItemRequest = youtube.playlistItems().list("snippet,contentDetails");
//[...]
playlistItemRequest.setFields("items(snippet/title,snippet/description,snippet/thumbnails/default/url,contentDetails/videoId),nextPageToken,pageInfo");
//[...]
videoItem.setId(item.getContentDetails().getVideoId());

I know that is an old question but It is important to identify which resources are we using to understand how to get the proper information. There are many resources in the YouTube API v3, but we usually use the search, video, playlist and playlistItems.
According to the documentation the following JSON structure shows the format of a playlistItems resource:
{
"kind": "youtube#playlistItem",
"etag": etag,
"id": string,
"snippet": {
"publishedAt": datetime,
"channelId": string,
"title": string,
"description": string,
"thumbnails": {
(key): {
"url": string,
"width": unsigned integer,
"height": unsigned integer
}
},
"channelTitle": string,
"playlistId": string,
"position": unsigned integer,
"resourceId": {
"kind": string,
"videoId": string,
}
},
"contentDetails": {
"videoId": string,
"startAt": string,
"endAt": string,
"note": string,
"videoPublishedAt": datetime
},
"status": {
"privacyStatus": string
}
}
From this structure, we may suppose that there are three ways to get the videoId. But first it is important to know how we going to define the PARTS and the FIELDS of the resource.
To define the PARTS we use this code:
YouTube.PlaylistItems.List list = youtube.playlistItems().list("snippet");
In the previous line, "snippet" identifies a property that contains numerous fields (or child properties), including the title, description, position, and resourceId, so when we set "snippet" the API's response will contain all of those child properties.
Now, we also can limit the previous properties if we define the FIELDS. For example, in this code:
list.setFields("items(id/videoId,snippet/title,snippet/description," +
"snippet/thumbnails/default/url)");
If we call list.execute(), it will show an error because we didn't define id in the PARTS properties. Also, according to the JSON structure, id is a String and does not contains videoId as a child property. Ah!, but we can extract videoId from the resourceId? -Well, the answers is YES/NO. -Why so? Come on Teo, the JSON structure shows it clearly. -Yes, I can see that, but the documentation says:
If the snippet.resourceId.kind property's value is youtube#video, then this property will be present and its value will contain the ID that YouTube uses to uniquely identify the video in the playlist.
This means that sometimes may not be available. -Then, how we can get the videoId? -Well, we can add id or contentDetails to the PARTS resources. If we add id then defines fields like this:
YouTube.PlaylistItems.List list = youtube.playlistItems().list("id,snippet");
list.setFields("items(id,snippet/title,snippet/description," +
"snippet/thumbnails/default/url)");
If we add contentDetails then defines fields like this:
YouTube.PlaylistItems.List list = youtube.playlistItems()
.list("snippet,contentDetails");
list.setFields("items(contentDetails/videoId,snippet/title,snippet/description," +
"snippet/thumbnails/default/url)");
I hope this helps you guys.

id/videoId doesnt exist.
There is an id and a snippet/resourceId/videoId.
So my guess is your setfields aren't right.

Related

How to upsert nested value using Spring-Data for Mongodb

I am trying to update the following JSON doc in mongodb so that a new document will be created if there is not one matching the "altKey", but if there is a document matching the altKey, any matching "records" will have their "domain" set and their "counts" incremented. I have a requirement that the JSON structure not change and that Spring-Data for mongodb is used.
{
"altKey": "value"
"records": {
"randomName1" {
"domain": "domainValue",
"count": 3
},
"randomName2" {
"domain": "domainValue2",
"count": 5
},
...
"randomNameN" {
"domain": "domainValueN",
"count": 4
}
}
}
The relevent portion of the class I have been attempting to do the update with is:
#Autowired
private MongoTemplate mongoTemplate;
#Override
public void increment(Doc doc) {
Query query = new Query().addCriteria(Criteria.where("altKey").is(doc.getAltKey());
Update update = new Update();
update.setOnInsert("altKey", doc.getAltKey());
for (final Map.Entry<String, RecordData> entry :
doc.getRecords().entrySet()) {
String domainKey = format("records.{0}.domain", entry.getKey());
String domainValue = entry.getValue().getDomain();
update.set(domainKey, domainValue);
String countKey = format("records.{0}.count", entry.getKey());
Integer countValue = entry.getValue().getCount();
update.inc(countKey, countValue);
}
mongoTemplate.upsert(query, update, Doc.class);
}
When I attempt to call the increment method the "altKey" field is successfully persisted, but none of the records persist and I am not sure of why that is. I believe the reason is my attempt to use mongo dot operation for the key when doing the set and inc update portions (ie "records.randomNameN.domain" or "records.randomNameN.count") but I haven't been able to find an alternate way to configure the Update object when I don't know until run time what the name of a particular record will be.
Anyone out there know how to set up the Update object to handle setting nested fields?

Iterate a JSON Object of Objects Firebase

I'm using firebase4j (a firebase library for Java, I know it is much better to go with node, I just wanted to try to do it with Java). In my database I need to persist the url of images with a bunch of the picture's information. The thing is that the picture url itself is very deep into the JSON
"users" : {
"aCategory" : {
"aUser" : {
"photos" : {
"photoUid1" : [ {
"value1" : false,
"value2" : "qwerty",
"score" : 40,
"url" : "http://someurl.com"
}
That is why I am trying to create an index for the pictures ordered by score, containing the url pointing to the location of the photo object in the firebase database. Here is where the issue begins. Firebase4j does not let you push, to a list for example, so the index ends up with this format:
{
"-UID1": {
"firebaseImgUrl": "users/aCategory/aUser/photos/photoUid1",
"score": 31
},
"-UID2": {
"firebaseImgUrl": "users/aCategory/aUser/photos/photoUid2",
"score": 30
}
}
I already added the rule ".indexOn" in order for firebase to answer with the right photos when asked for http://firebaseurl.com/users/...?orderBy="score"&limitToFirst=10, which is what I'm doing. I would like to know how should I iterate a JSON object of object as shown in the example above. I'm receiving the data from an Angular 4 client. I've tried a number of methods which haven't worked for me:
result: Photo[] = [];
for(let key in json){
console.log(key); //prints the UIDs
console.log(key.url); //url is not a property of string
//thus
result.push(new Photo(key.url, key.score)); //not working
}
The key is only a string, indicating the keys in your json. You should use it to access your object, like this:
result: Photo[] = [];
for(let key in json){
result.push(new Photo(json[key].firebaseImgUrl, json[key].score));
}

400 - bad request - request is syntactically incorrect

this is my code
var myObj =
{
"id": 0,
"createdDate": "12-12-2014 12:00:00",
"fromEmail": "abc#gmail.com",
"sampleBooleanValue": false,
"extraDescrition":"ssfsvgsf",
"sampleArraay":[{"arrayElem1"}, {"arrayElem2"}]
};
console.log(downtime1);
$rootScope.httpPost('createMyObj/', myObj).success(function (successdata) {
console.log(successdata);
}).error(function (errordata) {
console.log(errordata);
});
I have my REST endpoint created with URI createMyObj but as soon As I hit submit I get 400-bead request - the request submitted is syntactically incorrect error.
Is my JSON in correct format?
EDIT:
Here is my corrosponding Java bean
public class MyObj {
#Id
private int id;
private String fonEmail;
#ElementCollection
private List<String> sampleArraay;
private ZonedDateTime createdDate;
private Boolean sampleBooleanValue;
private String extraDescription;
Your array from the sampleArraay field is invalid. Try:
var myObj = {
"id": 0,
"createdDate": "12-12-2014 12:00:00",
"fromEmail": "abc#gmail.com",
"sampleBooleanValue": false,
"extraDescrition":"ssfsvgsf",
"sampleArraay":["arrayElem1", "arrayElem2"]
};
console.log(downtime1);
$rootScope.httpPost('createMyObj/', myObj).success(function (successdata) {
console.log(successdata);
})
.error(function (errordata) {
console.log(errordata);
});
"sampleArraay":[{"arrayElem1"}, {"arrayElem2"}]
Looks to be wrong. Were you planning for the elements of sampleArraay to be nested objects?
Also at the risk of being flippant, the spelling in your example, words like "Array" and "Description" are wrong. Could it be a case of being spelled wrong in one place and not in the other?
One thing I like to do when I get 400 errors like this is progressively simplify the object I am trying to send by commenting out elements until I get to the culprit.
I did this on JSFiddle.com (a great resource) with your code and a simple alert statement to confirm the array problem.

Plain string template query for elasticsearch through java API?

I have a template foo.mustache saved in {{ES_HOME}}/config/scripts.
POST to http://localhost:9200/forward/_search/template with the following message body returns a valid response:
{
"template": {
"file": "foo"
},
"params": {
"q": "a",
"hasfilters": false
}
}
I want to translate this to using the java API now that I've validated all the different components work. The documentation here describes how to do it in java:
SearchResponse sr = client.prepareSearch("forward")
.setTemplateName("foo")
.setTemplateType(ScriptService.ScriptType.FILE)
.setTemplateParams(template_params)
.get();
However, I would instead like to just send a plain string query (i.e. the contents of the message body from above) rather than build up the response using the java. Is there a way to do this? I know with normal queries, I can construct it like so:
SearchRequestBuilder response = client.prepareSearch("forward")
.setQuery("""JSON_QUERY_HERE""")
I believe the setQuery() method wraps the contents into a query object, which is not what I want for my template query. If this is not possible, I will just have to go with the documented way and convert my json params to Map<String, Object>
I ended up just translating my template_params to a Map<String, Object> as the documentation requires. I utilized groovy's JsonSlurper to convert the text to an object with a pretty simple method.
import groovy.json.JsonSlurper
public static Map<String,Object> convertJsonToTemplateParam(String s) {
Object result = new JsonSlurper().parseText(s);
//Manipulate your result if you need to do any additional work here.
//I.e. Programmatically determine value of hasfilters if filters != null
return (Map<String,Object>) result;
}
And you could pass in the following as a string to this method:
{
"q": "a",
"hasfilters": true
"filters":[
{
"filter_name" : "foo.untouched",
"filters" : [ "FOO", "BAR"]
},
{
"filter_name" : "hello.untouched",
"list" : [ "WORLD"]
}
]
}

Accessing Books API through AppEngine fails with error code 400

I'm getting following error when accessing Google Books APIs from Google AppEngine Application.
API key for server application is used.
But if you run application locally in eclipse there is no problem.
{
"code" : 403,
"errors" : [ {
"domain" : "global",
"message" : "Cannot determine user location for geographically restricted operation.",
"reason" : "unknownLocation"
} ],
"message" : "Cannot determine user location for geographically restricted operation."
}
There is not enough information on this error scenario.
Any help is appreciated. Thanks.
Well, this may be because the IP cannot be used to locate the user. It makes sense looking at the error message and with some googling here:
https://productforums.google.com/forum/#!topic/books-api/88Ml3YIpvLw
Try adding &country=GB to the end of the request, or whichever 2 letter represent the country which you are wanting to search from. (More here: http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)
This answer is mainly from the answer in the given link, however it appears to work and took some looking for. I hope it helps.
This following code solved my problem using Google Books API itself.
///////////////////////////////////////////////////
UrlFetchTransport url = new UrlFetchTransport();
final Books books = new Books.Builder(
url, jsonFactory, null)
.setApplicationName(APPLICATION_NAME)
.setGoogleClientRequestInitializer(
new GBookRequest()).build();
List volumesList = books.volumes().list("isbn:9780199562855");
// Execute the query.
Volumes volumes = volumesList.execute();
if (volumes.getTotalItems() == 0 || volumes.getItems() == null) {
log.info("No matches found in GBooks.");
return null;
}
///////////////////////////////////////////////////
public class GBookRequest extends BooksRequestInitializer {
private static String apiKey = "xxxxxx";
public GBookRequest() {
super(apiKey);
}
#Override
public void initializeBooksRequest(BooksRequest request)
throws IOException {
request.set("country", "US");
}
}
///////////////////////////////////////////////////

Categories

Resources