Is there any way to order the subscription list of Youtube channels by recently subscribed?
youtube
.subscriptions()
.list("snippet")
.setOrder("")// relevance, unread, alphabetical
.setMaxResults((long) 1000) // it is not affecting, the max limit is 50
.setMine(true)
.execute();
According to documents, I can only get max 50 items at a time, and I have only three order type parameters relevance, unread, alphabetical.
But I need to reach the channel I subscribed lastly. I would be really appreciated it if anybody helps me to handle this.
Thanks in advance!
According to the docs, you have the following parameter at your disposal:
myRecentSubscribers (boolean)
This parameter can only be used in a properly authorized request. Set this parameter's value to true to retrieve a feed of the subscribers of the authenticated user in reverse chronological order (newest first).
Note that this parameter only supports retrieval of the most recent 1000 subscribers to the authenticated user's channel. To retrieve a complete list of subscribers, use the mySubscribers parameter. That parameter, which does not return subscribers in a particular order, does not limit the number of subscribers that can be retrieved.
That is: do insert something like .setMyRecentSubscribers(true) in the sequence of setters of your code above. (Also you may remove the setChannelId setter call, since, by requiring from you to be authorized to invoke this endpoint, the API already knows the channel to which your call is referring to.)
Note also that the parameter's maxResults maximum value is 50. To receive only the most recent subscriber have .setMaxResults(1) in the setter sequence above.
If your want to obtain the list of all your subscriptions then there's the following parameter:
mine (boolean)
This parameter can only be used in a properly authorized request. Set this parameter's value to true to retrieve a feed of the authenticated user's subscriptions.
Have .setMine(true) (without .setChannelId) in your setters sequence.
You will have to invoke repeatedly the API's endpoint to get all of your subscriptions, since this endpoint provides paginated result sets. Upon obtaining all those subscriptions, sort them by snippet.publishedAt.
If you're only interested to obtain the most recent channel to which to have subscribed, instead of the sort algorithm, is sufficient to use the max algorithm (O(n) instead of O(n log n)) on the same property.
For an example of how to implement pagination in your code, have a look at some of the sample code provided by Google itself.
As I understand from your question, you want to check if you are following a specific youtube channel with help of Youtube Data API V3.
For that it is mentioned in the document that you can use forChannelId parameter.
Also Youtube Data API has a playground to let you see the results of your query. You can simply put a channelId in forChannelId field and result will return an empty array if you are not subscribed specified channel or result will return the data of that specified channel if you are subscribed to it.
You can do a simple request from your Java app to get results. In this code example I'm checking if authorized youtube API user is subscribed to Firebase Youtube Channel or not.
SubscriptionListResponse response = request.setForChannelId("UC_x5XG1OV2P6uZZ5FSM9Ttw")
.setMine(true)
.execute();
And response will include details of specified channel in the request you will make. I also share response of the request I shared above.
{
"kind": "youtube#SubscriptionListResponse",
"etag": "zCQ7lTwIBgdyVsQmbymEu-fUgjU",
"pageInfo": {
"totalResults": 1,
"resultsPerPage": 5
},
"items": [
{
"kind": "youtube#subscription",
"etag": "A-G_B0BnSqn7XtJi7BgHJEk9L3Q",
"id": "uTEDDg6jpPBwnsim9moHkataEljshwFopudOgIy34nk",
"snippet": {
"publishedAt": "2020-07-08T14:02:43.789000Z",
"title": "Google Developers",
"description": "The Google Developers channel features talks from events, educational series, best practices, tips, and the latest updates across our products and platforms.",
"resourceId": {
"kind": "youtube#channel",
"channelId": "UC_x5XG1OV2P6uZZ5FSM9Ttw"
},
"channelId": "UCC77fYySvfP7p-6QGaa-3lw",
"thumbnails": {
"default": {
"url": "https://yt3.ggpht.com/-Fgp8KFpgQqE/AAAAAAAAAAI/AAAAAAAAAAA/Wyh1vV5Up0I/s88-c-k-no-mo-rj-c0xffffff/photo.jpg"
},
"medium": {
"url": "https://yt3.ggpht.com/-Fgp8KFpgQqE/AAAAAAAAAAI/AAAAAAAAAAA/Wyh1vV5Up0I/s240-c-k-no-mo-rj-c0xffffff/photo.jpg"
},
"high": {
"url": "https://yt3.ggpht.com/-Fgp8KFpgQqE/AAAAAAAAAAI/AAAAAAAAAAA/Wyh1vV5Up0I/s800-c-k-no-mo-rj-c0xffffff/photo.jpg"
}
}
}
}
]
}
Related
I've read that Get requests should be idempotent.
I'm making an android app with a list of articles. Both guest and authenticated users can view a list of articles, but authenticated also get favorited status.
To make a request idempotent, the authenticated user should request both /articles and a second request to get the favorite status of this article.
How professional developers make these things? What is the best practice?
I see 3 ways:
Return a combined result based on the user. for guests favorited: 0, for authenticated if favorited, favorited: 1
GET /articles (statefull)
[
{
"id":1,
"title":"First Article",
"favorited":1
},
{
"id":2,
"title":"Second Article",
"favorited":0
},
{
"id":3,
"title":"Third Article",
"favorited":1
}
]
Return stateless and make ​additional request to check the favorited status for this article ids if authenticated.
GET /articles (stateless)
[
{
"id":1,
"title":"First Article"
},
{
"id":2,
"title":"Second Article"
},
{
"id":3,
"title":"Third Article"
}
]
if authenticated get favorite statuses for article id 1, 2 and 3
GET /favorites?id=1,2,3
[
{
"id":1,
"favorited":1
},
{
"id":2,
"favorited":0
},
{
"id":3,
"favorited":1
}
]
Return stateless. After login user need to request endpoint to get all favorited ids, save them in the local client, and on every item display check from local if post id is favorite. Note some users have 300+ favorited articles
After login get all favorited ids, save in client.
GET /myFavoriteArticleIds
[
1,
3,
5,
9,
17
]
And then make stateless requests
GET /articles (stateless)
[
{
"id":1,
"title":"First Article"
},
{
"id":2,
"title":"Second Article"
},
{
"id":3,
"title":"Third Article"
}
]
You should be using only one API request GET /api/articles. Authorized requests should have the Authorization header value. Based on that the response could be filtered while serializing the result object.
We can have customized responses from API based on the Authorization header.
Refer to Baeldung - https://www.baeldung.com/jackson-serialize-field-custom-criteria
It would perhaps help to review the definitions of safe and idempotent as found in RFC 7231. The semantics of GET are safe, which means that all of the constraints of idempotent are satisfied, and some others.
In summary, safe means read-only.
But it doesn't tell you anything about representations, or resource design.
How professional developers make this things? What is best practice?
Think about how you would design a web site? One answer would be to have a page for anonymous users, and then a different page for administrators (which includes the extra information that the administrators need). The second page would be locked down so that only authorized users can get at it (which has some interesting implications for caching).
The same basic principles hold for an API.
To distinguish the difference between guest and authenticated cases, I would recommend you to use namespaces for all APIs.
Ex:
For authenticated users,
/api/articles - list of articles along with favorites
/api/articles/$article_id - single article information along with favorited time etc
For guest users,
/guest_api/articles - only the list of articles
/guest_api/articles/$article_id - only the article information
Based on the user type, the favorited flag can be returned in response.
User type can be passed a query parameter.
Example: GET /api/v1/articles?user=guest
I'd like to identify users beyond their username. Is there any way to identify users with a token/code/ID# that is static and will never change?
Simply because usernames are flexible and can be changed at any time meaning I cannot keep track users.
Dani you can track users by their user id, which stays static even if they change their username.
In Instagram's API example they use this endpoint: https://api.instagram.com/v1/users/{user-id}/?access_token=ACCESS-TOKEN
which gives the following response:
{
"data": {
"id": "1574083",
"username": "snoopdogg",
"full_name": "Snoop Dogg",
"profile_picture": "http://distillery.s3.amazonaws.com/profiles/profile_1574083_75sq_1295469061.jpg",
"bio": "This is my bio",
"website": "http://snoopdogg.com",
"counts": {
"media": 1320,
"follows": 420,
"followed_by": 3410
}
}
Depending on what data or which endpoints you are hitting beforehand, you should be able to get to the user ID and use that accordingly throughout your application.
I am trying to create an app using Google Fit Api and i am trying to get the total time of exercise (supposed that the exercise is walking) for the user. What i want basically is to get the value marked in below image :
Google Fit Time Screenshot
I was thinking to work with sessions (https://developers.google.com/fit/android/using-sessions) but i prefer to skip this if there is already something provided by Google. I know how to get the daily steps/calories/distance but i am not able to find anything to get the daily exercise time.
Let me describe what I found so far, but there is one issue left...
You can use the aggregate api and group by activity type. Here is an example with daily bucketing:
POST https://www.googleapis.com/fitness/v1/users/me/dataset:aggregate
{
"aggregateBy": [
{
"dataSourceId": "derived:com.google.activity.segment:com.google.android.gms:merge_activity_segments"
}
],
"endTimeMillis": "1481788800000",
"startTimeMillis": "1481702400000",
"bucketByTime": {
"period": {
"timeZoneId": "America/Los_Angeles",
"type": "day",
"value": 1
}
}
}
The call will return a number of records, each containing three values: activity type, duration in milliseconds, and number of segments. You can find the activity types at: https://developers.google.com/fit/rest/v1/reference/activity-types. You can add up the milliseconds for the activity types you are interested in.
Now, the issue - I have seen examples of mismatch of activity types between the API and Fit app. I don't know how widespread the mismatch is. See my question: Getting active time from Google Fit Rest API.
I am trying to get only sport type facebook events.
I am retreiving my events using the query below, but I want to filter these out by category. I have tried nested fields but I can't get the ones I need, I get everything back.
search?q=Brasov&type=event&fields=name,start_time,id,cover,owner
The events I am looking for have this category in the owner field.
"category": "Sports/recreation/activities",
"category_list": [
{
"id": "186982054657561",
"name": "Sports & Recreation"
}
Do you know any way I can get only the events that have this category_list id ?
That is not currently possible. I would suggest you to store the events you received from the API call and do a filter on your server (or client).
That is, can you send
{
"registration_ids": ["whatever", ...],
"data": {
"foo": {
"bar": {
"baz": [42]
}
}
}
}
or is the "data" member of the GCM request restricted to one level of key-value pairs? I ask b/c that limitation is suggested by the wording in Google's doc[1], where it says "data" is:
A JSON object whose fields represents the key-value pairs of the message's payload data. If present, the payload data it will be included in the Intent as application data, with the key being the extra's name. For instance, "data":{"score":"3x1"} would result in an intent extra named score whose value is the string 3x1 There is no limit on the number of key/value pairs, though there is a limit on the total size of the message. Optional.
[1] http://developer.android.com/guide/google/gcm/gcm.html#request
Just did a test myself and confirmed my conjecture.
Send a GCM to myself with this payload:
{
"registration_ids": ["whatever", ...],
"data": {
"message": {
"bar": {
"baz": [42]
}
}
}
}
And my client received it and parse the 'message' intent extra as this:
handleMessage - message={ "bar": { "baz": [42] } }
So the you can indeed do further JSON parsing on the value of a data key.
Although it appears to work (see other answers and comments), without a clear statement from Google, i would not recommend relying on it as their documentation consistently refers to the top-level members of the json as "key-value pairs". The server-side helper jar they provide [1] also reinforces this idea, as it models the user data as a Map<String, String>. Their Message.Builder.addData method doesn't even support non-string values, so even though booleans, numbers, and null are representable in json, i'd be cautious using those, too.
If Google updates their backend code in a way that breaks this (arguably-unsupported) usage, apps that relied on it would need an update to continue to work. In order to be safe, i'm going to be using a single key-value pair whose value is a json-stringified deep object [2]. My data isn't very big, and i can afford the json-inside-json overhead, but ymmv. Also, one of my members is a variable-length list, and flattening those to key-value pairs is always ugly :)
[1] http://developer.android.com/guide/google/gcm/server-javadoc/index.html (The jar itself is only available from within the Android SDK in the gcm-server/dist directory, per http://developer.android.com/guide/google/gcm/gs.html#server-app )
[2] e.g. my whole payload will look something like this:
{
"registration_ids": ["whatever", ...],
"data": {
"player": "{\"score\": 1234, \"new_achievements\": [\"hot foot\", \"nimble\"]}"
}
}
Scuse me if I'm wrong, Map<String, String> denotes key=string and value=string.
If string is a long unreasonable json extract which is UTF-8 formatted and well escaped. It stands to reason that should you call new JSONObject(receivedString); and it works then all other json calls follow.
Do not forget that raw JSON is a string! We do not need google to clarify how to work with strings..this is why your test worked!