Youtube Data Subscription API V3 not returning NextPage when submitted with mySubscribers - youtube-data-api

I am not getting "nextPageToken" in the response object when I tried to retrieve list of users who subscribed to our channels using YT Data API (v3) Subscription. For some reason YT not returning "nextPageToken" even though below channel has more than 100K subscribers so could you please advise me on how to be able to fetch next pages of subscribers. Same behavior happening when I tried with any of channels from our CMS account:
Request:
https://www.googleapis.com/youtube/v3/subscriptions?onBehalfOfContentOwner=xxxx&onBehalfOfContentOwnerChannel=xxxxxxxxxxx&fields=items(contentDetails,id,snippet(publishedAt,channelId),subscriberSnippet(title,description)),nextPageToken,pageInfo,tokenPagination&maxResults=50&mySubscribers=true&part=id,snippet,contentDetails,subscriberSnippet&key=xxxxxxxxxxxxxxxx
Here is sample response snippet (I trimmed out other 48 items from below list and intentionally masked out subscriber details)
{
"items": [
{
"snippet": {
"channelId": "UCUR8UieACc2QXl7waH821hQ",
"publishedAt": "2014-05-20T19:50:44.000Z"
},
"contentDetails": {
"newItemCount": 0,
"activityType": "all",
"totalItemCount": 51
},
"subscriberSnippet": {
"description": "",
"title": "Sebastian Brentsworth"
},
"id": "MVPSEm5kMooIHMvcBKqbtFJAp1dHw0GeHza2Iq5KXP"
},
{
"snippet": {
"channelId": "UCYs04YSyy1soNzyvsDljYVg",
"publishedAt": "2014-05-28T22:39:30.000Z"
},
"contentDetails": {
"newItemCount": 0,
"activityType": "all",
"totalItemCount": 51
},
"subscriberSnippet": {
"description": "",
"title": "Jason Chan"
},
"id": "Xd7_fS3FIA4rnSu6NXEfxF8trXzL8-LspvIuYtDMmc0"
}
],
"pageInfo": {
"resultsPerPage": 50,
"totalResults": 144403
}
}

"Known" (Hopefully also to Google) bug:
https://code.google.com/p/gdata-issues/issues/detail?id=7163 and youtube.subscriptions.list (api v3) - nextPageToken isn't available
For the time being, I've came up with a token generator as a workaround (see other SO post, or here: https://gist.github.com/pulsar256/f5621e85ef50711adc6f)

Related

YouTube Data API Get Channel by Handle

Introducing handles: A new way to identify your YouTube channel
Does the YouTube Data API support querying for a channel by it's #handle? This does not seem to be supported.
ex: https://www.youtube.com/#lionsgatemovies
forUsername param
GET https://www.googleapis.com/youtube/v3/channels?part=id,snippet&forUsername=#lionsgatemovies
{
"kind": "youtube#channelListResponse",
"etag": "RuuXzTIr0OoDqI4S0RU6n4FqKEM",
"pageInfo": {
"totalResults": 0,
"resultsPerPage": 5
}
}
id param
GET https://www.googleapis.com/youtube/v3/channels?part=id,snippet&id=#lionsgatemovies
{
"kind": "youtube#channelListResponse",
"etag": "RuuXzTIr0OoDqI4S0RU6n4FqKEM",
"pageInfo": {
"totalResults": 0,
"resultsPerPage": 5
}
}
None of the supported filter params seem to be appropriate:
{
"error": {
"code": 400,
"message": "No filter selected. Expected one of: mySubscribers, forUsername, mine, managedByMe, categoryId, id",
"errors": [
{
"message": "No filter selected. Expected one of: mySubscribers, forUsername, mine, managedByMe, categoryId, id",
"domain": "youtube.parameter",
"reason": "missingRequiredParameter",
"location": "parameters.",
"locationType": "other"
}
]
}
}
You can use Search API with q parameter set to #handle
curl \
'https://youtube.googleapis.com/youtube/v3/search?part=snippet&maxResults=25&q=%40kevinrooke&type=channel&key=[YOUR_API_KEY]'
{
"kind": "youtube#searchListResponse",
"etag": "AYlro9VG2vMtdew4OQiWoQM8Rs0",
"regionCode": "LT",
"pageInfo": {
"totalResults": 1,
"resultsPerPage": 1
},
"items": [
{
"kind": "youtube#searchResult",
"etag": "ls9E_ctoa-RLsqznJwxWlHHIE1s",
"id": {
"kind": "youtube#channel",
"channelId": "UCTdxV_ItCZMayyzGkw7P_qQ"
},
"snippet": {
"publishedAt": "2017-05-27T03:56:38Z",
"channelId": "UCTdxV_ItCZMayyzGkw7P_qQ",
"title": "Kevin Rooke",
"description": "Interviews with the builders bringing the Lightning Network to life. ⚡kerooke#fountain.fm.",
"thumbnails": {
"default": {
"url": "https://yt3.ggpht.com/ytc/AMLnZu-SpmaNjx7KOMqs5Cr7ZthU60BaQApzt89_dHOlcg=s88-c-k-c0xffffffff-no-rj-mo"
},
"medium": {
"url": "https://yt3.ggpht.com/ytc/AMLnZu-SpmaNjx7KOMqs5Cr7ZthU60BaQApzt89_dHOlcg=s240-c-k-c0xffffffff-no-rj-mo"
},
"high": {
"url": "https://yt3.ggpht.com/ytc/AMLnZu-SpmaNjx7KOMqs5Cr7ZthU60BaQApzt89_dHOlcg=s800-c-k-c0xffffffff-no-rj-mo"
}
},
"channelTitle": "Kevin Rooke",
"liveBroadcastContent": "none",
"publishTime": "2017-05-27T03:56:38Z"
}
}
]
}
As of this moment (17th Nov 2022), YouTube has yet to update the Data API with #handle support.
The channelId was scattered around in the Html. You can easily parse them after fetching the url with the handle.
const html = await(await fetch(url)).text()
const channelId = html.match(/(?<=channelId(":"|"\scontent="))[^"]+/g)[0];
Following is the python snippet while we are waiting for YouTube API's official support. This is inspired by goodhyun's wonderful thoughts.
import requests
import re
# return YouTube channel id via handle or False if failed
def scraping_get_channel_id_from_handle(handle:str):
if handle.find('#') == -1:
handle = '#' + handle
url = 'https://www.youtube.com/' + handle
resp = requests.get(url)
if resp.status_code == 200:
found = re.findall('"channelId":"([^"]*)","title"', resp.text)
return found[0]
else:
return False

How do I get the comments on a video that have been liked by the video creator?

For example,
on a video called "B" created by a channel called "A",
is it possible to get a specific comment that "A" has liked?
Currently, I think I can only get the total number of likes for a particular comment on a video called "B" created by a channel called "A".
One more time YouTube Data API v3 doesn't provide a basic feature.
I recommend you to try out my open-source YouTube operational API. Indeed by fetching https://yt.lemnoslife.com/commentThreads?part=snippet,replies&videoId=VIDEO_ID&order=ORDER (ORDER can be either time or relevance, but note that this latter returns less comments), you will get the video comments with the isHearted you are looking for in item["snippet"]["topLevelComment"]["snippet"]["isHearted"].
The YouTube video mWdFMNQBcjs is a good video to test this feature of my API because it doesn't have too many comments while having both pagination mechanism for top level comments and answers, in addition to have its first comment hearted and pinned. With this video id you would get:
{
"kind": "youtube#commentThreadListResponse",
"etag": "NotImplemented",
"pageInfo": {
"totalResults": 67,
"resultsPerPage": 20
},
"nextPageToken": "Eg0SC21XZEZNTlFCY2pzGAYy3gIKtAJnZXRfcmFua2VkX3N0cmVhbXMtLUNxVUJDSUFFRlJlMzBUZ2FtZ0VLbFFFSTJGOFFnQVFZQnlLS0FkdEtUa2V3RXhLY2Q3U3NodkZrZnBjbHlYVEZCTUxWV1RmVUdiUWtGbjFoa3FpNUlucVE2ZmMyRVptc1BGbG15UmhCNXo1LWFhTmNWelc0UGFYdGRMYzd0SUVmRlZmYzlmbUN4SktkVXY0MS1FcWZadXNrQnhrc2g4ZjdnUHdpZHpXM2M4SFA3RGJjVjdCZWtLTWwtMHJXa0phVU0zRW9NU05wS0xjZ1o0aHFpRWRabWNENDE0bVFQQkFVRWdVSWhpQVlBQklGQ0lnZ0dBQVNCUWlYSUJnQUVnVUlpU0FZQUJJSENJY2dFQUVZQUJJSENJVWdFQlFZQVJnQiIRIgttV2RGTU5RQmNqczAAeAEoFEIQY29tbWVudHMtc2VjdGlvbg==",
"items": [
{
"kind": "youtube#commentThread",
"etag": "NotImplemented",
"id": "UgzT9BA9uQhXw05Q2Ip4AaABAg",
"snippet": {
"topLevelComment": {
"kind": "youtube#comment",
"etag": "NotImplemented",
"id": "UgzT9BA9uQhXw05Q2Ip4AaABAg",
"snippet": {
"textOriginal": "Twenty-three",
"isHearted": true,
"authorDisplayName": null,
"authorHandle": "#user-wl1ce4xg4j",
"authorProfileImageUrls": [
{
"url": "https:\/\/yt3.ggpht.com\/ytc\/AMLnZu_3pI88H9gEgJtksqziDFfJj3PSO1E-_7Z5Tn_GJtTMyp7wglMOOAuYSEs_u0LR=s48-c-k-c0x00ffffff-no-rj",
"width": 48,
"height": 48
},
...
],
"authorChannelId": {
"value": "UCv_LqFI-0vMVYgNR3TeB3zQ"
},
"likeCount": "",
"publishedAt": "3 weeks ago",
"wasEdited": false,
"isPinned": true,
"authorIsChannelOwner": true,
"videoCreatorHasReplied": true,
"totalReplyCount": 23,
"nextPageToken": "Eg0SC21XZEZNTlFCY2pzGAYygwEaUBIaVWd6VDlCQTl1UWhYdzA1UTJJcDRBYUFCQWciAggAKhhVQ3ZfTHFGSS0wdk1WWWdOUjNUZUIzelEyC21XZEZNTlFCY2pzQAFICoIBAggBQi9jb21tZW50LXJlcGxpZXMtaXRlbS1VZ3pUOUJBOXVRaFh3MDVRMklwNEFhQUJBZw=="
}
}
}
},
...
]
}
As YouTube Data API v3 CommentThreads: list and Comments: list there are two pagination mechanisms:
the top level pagination (using here
Eg0SC21XZEZNTlFCY2pzGAYyiwEKT0FEU0pfaTJYUjJDTWhJQ2ZGWWdoV2NGUkpqWXRDX1FMQVZYVE9JOU1hUjZmQ0tEUDBkcWpacmQzOG5Yc0kwYUFGUnJFTkdkMmpINlZaMlEiESILbVdkRk1OUUJjanMwAXgBKBQwAUIhZW5nYWdlbWVudC1wYW5lbC1jb21tZW50cy1zZWN0aW9u
for the nextPageToken) browse top level comments
the answers pagination (using here
Eg0SC21XZEZNTlFCY2pzGAYygwEaUBIaVWd6VDlCQTl1UWhYdzA1UTJJcDRBYUFCQWciAggAKhhVQ3ZfTHFGSS0wdk1WWWdOUjNUZUIzelEyC21XZEZNTlFCY2pzQAFICoIBAggCQi9jb21tZW50LXJlcGxpZXMtaXRlbS1VZ3pUOUJBOXVRaFh3MDVRMklwNEFhQUJBZw==
for the nextPageToken) browse answers to a given comment

YouTube Data API Channel.list function

For the channel.list function of the YouTube API are you able to call statistics for any channel on YouTube? Reviewing the below call parameters it seems all require you to be the owner of that channel to receive any information on that channel.
I've also tried the API test to see if I can receive data by username for the channel but doesn't seem to work. Beginner so if anyone could help out I'd much appreciate it!
https://developers.google.com/youtube/v3/docs/channels/list?apix_params=%7B%22forUsername%22%3A%22Peter%20McKinnon%22%7D
You do not need to be the owner of the channel you just need the channel Id. You can tests this using the try me on channel.list its a public api call.
request
GET https://www.googleapis.com/youtube/v3/channels?part=snippet%2CcontentDetails%2Cstatistics&id=UCeY0bbntWzzVIaj2z3QigXg&key=[YOUR_API_KEY] HTTP/1.1
Accept: application/json
response
{
"kind": "youtube#channelListResponse",
"etag": "y2BDT1Qkcr2Fm2FAHjDfG6Gn8Sc",
"pageInfo": {
"resultsPerPage": 1
},
"items": [
{
"kind": "youtube#channel",
"etag": "VCwefXyl53bCqIREF0zJeTfxZXk",
"id": "UCeY0bbntWzzVIaj2z3QigXg",
"snippet": {
"title": "NBC News",
"description": "» Subscribe to NBC News:",
"customUrl": "nbcnews",
"publishedAt": "2006-07-19T20:46:03Z",
"thumbnails": {
"default": {
"url": "https://yt3.ggpht.com/a/AATXAJzjPejETKc2lrL43-9gFFWRL9WKwEmOIvtbWyait1c=s88-c-k-c0xffffffff-no-rj-mo",
"width": 88,
"height": 88
},
"medium": {
"url": "https://yt3.ggpht.com/a/AATXAJzjPejETKc2lrL43-9gFFWRL9WKwEmOIvtbWyait1c=s240-c-k-c0xffffffff-no-rj-mo",
"width": 240,
"height": 240
},
"high": {
"url": "https://yt3.ggpht.com/a/AATXAJzjPejETKc2lrL43-9gFFWRL9WKwEmOIvtbWyait1c=s800-c-k-c0xffffffff-no-rj-mo",
"width": 800,
"height": 800
}
},
"localized": {
"title": "NBC News",
"description": "» Subscribe to NBC News: "
}
},
"contentDetails": {
"relatedPlaylists": {
"likes": "",
"favorites": "",
"uploads": "UUeY0bbntWzzVIaj2z3QigXg",
"watchHistory": "HL",
"watchLater": "WL"
}
},
"statistics": {
"viewCount": "1942288925",
"commentCount": "0",
"subscriberCount": "3700000",
"hiddenSubscriberCount": false,
"videoCount": "25734"
}
}
]
}

Youtube Data API - /channels Endpoint not Returning Smaller Users

I am creating a networking app for musicians. I was wanting to use the Youtube Data API to let users connect their Youtube channel to their profile within my app. I got everything in place and working via making requests to URLs similar to https://www.googleapis.com/youtube/v3/channels?part=snippet,statistics&forUsername=PewDiePie&key=[YOUR_API_KEY]. This works great and returns this JSON:
{ "kind": "youtube#channelListResponse", "etag": "\"p4VTdlkQv3HQeTEaXgvLePAydmU/bj_rirVFbrVoTIOa6lCGdaXaG5M\"", "pageInfo": { "totalResults": 1, "resultsPerPage": 5 }, "items": [ { "kind": "youtube#channel", "etag": "\"p4VTdlkQv3HQeTEaXgvLePAydmU/Blp06js4r7j93y1EfKve84oXWpo\"", "id": "UC-lHJZR3Gqxm24_Vd_AJ5Yw", "snippet": { "title": "PewDiePie", "description": "I make videos.", "publishedAt": "2010-04-29T10:54:00.000Z", "thumbnails": { "default": { "url": "https://yt3.ggpht.com/a/AGF-l79FVckie4j9WT-4cEW6iu3gPd4GivQf_XNSWg=s88-c-k-c0xffffffff-no-rj-mo", "width": 88, "height": 88 }, "medium": { "url": "https://yt3.ggpht.com/a/AGF-l79FVckie4j9WT-4cEW6iu3gPd4GivQf_XNSWg=s240-c-k-c0xffffffff-no-rj-mo", "width": 240, "height": 240 }, "high": { "url": "https://yt3.ggpht.com/a/AGF-l79FVckie4j9WT-4cEW6iu3gPd4GivQf_XNSWg=s800-c-k-c0xffffffff-no-rj-mo", "width": 800, "height": 800 } }, "localized": { "title": "PewDiePie", "description": "I make videos." }, "country": "US" }, "statistics": { "viewCount": "24334379402", "commentCount": "0", "subscriberCount": "102000000", "hiddenSubscriberCount": false, "videoCount": "4054" } } ] }
Most of my app's users will be smaller musicians, likely with less than 10k youtube subscribers. Take my sister for example, this is a link to her youtube channel: https://www.youtube.com/channel/UCe4Eogv2uGaKUe4x3VNrwsg.
Whenever trying to search for her Youtube channel with the API via https://www.googleapis.com/youtube/v3/channels?part=snippet,statistics&forUsername=Audrey_Chopin&key=[YOUR_API_KEY] (and variations such as replacing Audrey_Chopin with Audrey%20Chopin or Audrey+Chopin) yield no results: { "kind": "youtube#channelListResponse", "etag": "\"p4VTdlkQv3HQeTEaXgvLePAydmU/zJL80hJ0IwMo5wddECFapC8I6Q4\"", "pageInfo": { "totalResults": 0, "resultsPerPage": 5 }, "items": [] }.
Are smaller users not supposed to be returned from this endpoint? If so, is there any way I can implement users to search for their profile without forcing the user to do the OAuth process, i.e. signing into their Youtube account?
It seems that using the /search endpoint works better for smaller channels, though there is less information available in this endpoint (I am unable to get subscriber count and video count, which was included in the "statistics" part of the /channel endpoint).
So updating
https://www.googleapis.com/youtube/v3/channels?part=snippet,statistics&forUsername=Audrey_Chopin&key=[YOUR_API_KEY]
to
https://www.googleapis.com/youtube/v3/search?part=snippet&channelType=any&maxResults=50&order=relevance&q=Audrey%20Chopin&type=channel&key=[YOUR_API_KEY]
yielded smaller channels, though without as much data as when using the /channel endpoint.
Still curious, if anybody knows, why the /channel endpoint does not return smaller channels.
Since you know the user's channel id, simply issue a query to the Channels endpoint on the URL:
https://www.googleapis.com/youtube/v3/channels?part=...&id=$CHANNEL_ID&key=$APP_KEY,
and you'll obtain all public (i.e. non-private) info attached to the referenced channel -- without needing any further authentication. Of course you can specify the part parameter as you see fit.
On the other hand, please note that querying the Search.List endpoint for snippet part is much more costly than querying the Channels.List endpoint for both snippet and statistics parts: 100 vs. 5 quota points.

Why are my chatbot refresh cards in Teams not refreshing?

I am serving out O365 connector cards to my teams channel in my chatbot, for the user to use an HttpPost action to send data back to the bot.
Here is a sample invoke message when the user saves:
{
"name": "actionableMessage/executeAction",
"type": "invoke",
"timestamp": "2018-06-16T20:58:24.388Z",
"localTimestamp": "2018-06-16T21:58:24.388+01:00",
"id": "snip",
"channelId": "msteams",
"serviceUrl": "https://smba.trafficmanager.net/emea-client-ss.msg/",
"from": {
"id": "snip",
"name": "my name",
"aadObjectId": "snip"
},
"conversation": {
"conversationType": "personal",
"id": "long conversation id"
},
"recipient": {
"id": "bot id",
"name": "bot name"
},
"entities": [
{
"locale": "en-US",
"country": "US",
"platform": "Web",
"type": "clientInfo"
}
],
"channelData": {
"tenant": {
"id": "tenant id"
},
"source": {
"name": "message"
}
},
"replyToId": "message id",
"value": {
"body": "{\"sportType\":\"1\", \"tournamentName\":\"FIFA Soccer World Cup\",\"startTime\":\"2018-06-14T03: 00: 00.000Z\", \"endTime\":\"2018-07-16T07: 30: 00.000Z\", \"timeZone\":\"Russian Standard Time\", \"tournamentId\": \"1\"}",
"actionId": "SaveTournament"
}
}
In response to a save card, I am returning an ActionCard in the response body, and I am including an HTTP header "CARD-UPDATE-IN-BODY" with a value "true". Here is a sample response message:
{
"#type": "ActionCard",
"inputs": [
{
"#type": "TextInput",
"isMultiline": true,
"maxLength": 500.0,
"id": "SaveStatus",
"isRequired": false,
"title": "Save Status",
"value": "You updated the tournament FIFA Soccer World Cup running from 6/14/2018 to 7/16/2018 in timezone Russian Standard Time"
}
],
"actions": [
{
"#type": "HttpPOST",
"body": "{\"tournamentId\": \"1\"}",
"name": "Update FIFA Soccer World Cup again",
"#id": "UpdateTournament#1"
}
],
"name": "Save Tournament",
"#id": "SaveTournament"
}
I have traced this in my web app so I know that is what is being returned to the bot framework middleware.
In my teams app in the browser,when I trace the response message with Fiddler, the card invoke response is not getting the refresh card I send, it is just getting a generic 200 response with an empty response body. Can anyone point me to a demo of refresh cards that work with Teams, or tell me what's wrong with my messages?
Teams doesn't support updating the original card by responding to the invoke message. Instead, you need to explicitly update the message by calling the Bot Framework API (see https://learn.microsoft.com/en-us/microsoftteams/platform/concepts/bots/bot-conversations/bots-conversations#updating-messages).
The incoming invoke message has the information you need to update the original message:
<serviceurl>/v3/conversations/<conversationid>/activities/<activityid>
<serviceurl>: serviceUrl
<conversationid>: conversation.id
<activityid>: replyToId
(The details of how to update a message depends on exactly which SDK you're using, but in the end you'll need those 3 items to refer to the message.)

Resources