I'm inserting videos on youtube using API in PHP version. But I'm not able to include a highlight comment in the videos. In the youtube documentation the example is in json , and as I'm doing it in php it just doesn't work.
See part of my code is like this:
// Create a snippet with title, description, tags and category ID
// Create an asset resource and set its snippet metadata and type.
// This example sets the video's title, description, keyword tags, and
// video category.
$snippet = new Google_Service_YouTube_VideoSnippet();
$snippet->setTitle("Cats are cute #".$filme['Data ID']);
$snippet->setDescription($filme['titulo']);
$snippet->setTags('cats','cutecats','cute');
// Numeric video category. See
// https://developers.google.com/youtube/v3/docs/videoCategories/list
$snippet->setCategoryId("19");
// Set the video's status to "public". Valid statuses are "public",
// "private" and "unlisted".
$status = new Google_Service_YouTube_VideoStatus();
$status->privacyStatus = "public";
// Associate the snippet and status objects with a new video resource.
$video = new Google_Service_YouTube_Video();
$video->setSnippet($snippet);
$video->setStatus($status);
And the youtube suggestion to include comments using the API is this:
{
"snippet": {
"channelId": "UC_x5XG1OV2P6uZZ5FSM9Ttw",
"topLevelComment": {
"snippet": {
"textOriginal": "This video is awesome!"
}
},
"videoId": "MILSirUni5E"
}
}
I tried like this and it didn't work:
$snippet->textOriginal('My comment');
How can I submit a featured comment using youtube API in php?
Since mid-Jan 2022, I noticed that the YouTube Data API's list method no longer returns liveStreamingDetails.concurrentViewers. This happens to me with all live videos in several channels.
https://youtube.googleapis.com/youtube/v3/videos?part=liveStreamingDetails&id=[VIDEO_ID]&key=[YOUR_API_KEY]
Response:
{
"kind": "youtube#videoListResponse",
"etag": "ETAG_ID",
"items": [
{
"kind": "youtube#video",
"etag": "ETAG_ID",
"id": "VIDEO_ID",
"liveStreamingDetails": {
"actualStartTime": "YYYY-MM-DDTHH:MM:SSZ",
"actualEndTime": "YYYY-MM-DDTHH:MM:SSZ",
"scheduledStartTime": "YYYY-MM-DDTHH:MM:SSZ"
}
}
],
"pageInfo": {
"totalResults": 1,
"resultsPerPage": 1
}
}
Document references:
https://developers.google.com/youtube/v3/docs/videos/list
https://developers.google.com/youtube/v3/docs/videos#liveStreamingDetails.concurrentViewers
From the second doc (bold is mine):
The property and its value will be present if the broadcast has current viewers and the broadcast owner has not hidden the viewcount for the video.
As far as I know, none of the channels nor videos that I tested with have blocked viewcounts.
Is there any other way to retrieve the concurrent viewers programmatically?
"concurrentViewers" is bugged since last month.
Example:
VideoId: 1iw-7ZCVayU
TIME RETURNED CONCURRENT VIEWERS
09:57PM 26884
09:59PM 26850
**10:00PM 16**
10:01PM 26930
10:02PM 27049
10:03PM 26864
**10:04PM 17**
10:05PM 26987
10:06PM 27154
API response includes some incorrect values among correct values. It happens in many broadcasts since last month.
More recent examples:
VideoId: IzbldpY6rYA
TIME RETURNED CONCURRENT VIEWERS
05:16PM 17534
05:17PM 17570
**05:18PM 12**
05:19PM 17615
05:20PM 17720
05:21PM 18063
**05:22PM 10**
05:23PM 18899
**05:24PM 10**
VideoId: Es0W77JUxbk
TIME RETURNED CONCURRENT VIEWERS
07:30PM 5289
07:31PM 5250
**07:32PM 7**
07:33PM 5265
07:34PM 5192
07:35PM 5119
**07:36PM 6**
07:37PM 5117
When using the youtube API to get the list of my subscriptions and all the related details I get a number of information from the snippet and contentDetails part of the response object.
When I call the service from my script the contentDetails.newItemCount always return zero, this should indicate the number of new videos on the channel since last time I've opened the channel. The contentDetails.totalItemCount (total number of videos for the channel) is accurate instead.
In contrast if I run the same query through the google api explorer, the same variable contains the correct information and not zero.
The call I make from my PHP script is exactly the same as the one run on the google api explorer so I can't explain or understand why I'm getting different results. The code I use is roughly the following
$this->_youtube = new Google_Service_YouTube($this->_connector->_googleClient);
$params = array('mine' => true,'maxResults'=>25,'order'=>'alphabetical');
$part = 'snippet,contentDetails';
$response = $this->_youtube->subscriptions->listSubscriptions(
$part,
$params
);
foreach ($response['items'] as $item) {
$this->_mysubscriptions[] = array(
'channelId'=>$item['snippet']['resourceId']['channelId'],
'title'=>$item['snippet']['title'],
'description'=>$item['snippet']['description'],
'thumb_default'=>$item['snippet']['thumbnails']['default']['url'],
'thumb_medium'=>$item['snippet']['thumbnails']['medium']['url'],
'thumb_high'=>$item['snippet']['thumbnails']['high']['url'],
'subscribedOn'=>$this->cleanDate($item['snippet']['publishedAt']),
'totalVideos'=>$item['contentDetails']['totalItemCount'],
'newVideos'=>$item['contentDetails']['newItemCount']);
}
This is how the object returned looks like (just removed few IDs from the response) from the google API explorer, while when I run it through my code I get the same data but the newItemCount is zero.
{
"kind": "youtube#subscription",
"snippet": {
"publishedAt": "2016-09-14T12:48:00.000Z",
"title": "Muselk",
"description": "\"Memes win games\" - Youtube.com/mrmuselk",
"resourceId": {
"kind": "youtube#channel",
"channelId": "UCd534c_ehOvrLVL2v7Nl61w"
},
"thumbnails": {
"default": {
"url": "https://yt3.ggpht.com/-iWlz7dePNz0/AAAAAAAAAAI/AAAAAAAAAAA/smtPKh-RLTU/s88-c-k-no-mo-rj-c0xffffff/photo.jpg"
},
"medium": {
"url": "https://yt3.ggpht.com/-iWlz7dePNz0/AAAAAAAAAAI/AAAAAAAAAAA/smtPKh-RLTU/s240-c-k-no-mo-rj-c0xffffff/photo.jpg"
},
"high": {
"url": "https://yt3.ggpht.com/-iWlz7dePNz0/AAAAAAAAAAI/AAAAAAAAAAA/smtPKh-RLTU/s240-c-k-no-mo-rj-c0xffffff/photo.jpg"
}
}
},
"contentDetails": {
"totalItemCount": 792,
"newItemCount": 4,
"activityType": "all"
}
I've looked through the revision history but can't find any reference of modifications made to this specific property of the contentDetails object
There is a bug filed with google on this property but it refers to a different behaviour.
Wondering if this happens to other as well, or if somebody can give some hints on how this works or don't.
I would like to fetch details of a YouTube channel which has a custom URL, like https://www.youtube.com/c/pratiksinhchudasamaisawesome.
Custom channel URLs follow this format: https://www.youtube.com/c/{custom_channel_name}.
I can fetch the details of YouTube channels by Channel ID and username without any issues. Unfortunately, I need to use the custom channel URL which is the only time I encounter this issue.
I developed my app few months ago, and the custom channel URL was working up until a few days ago. Now, the YouTube data API does not return anything for the YouTube custom channel URL if I try get details using their custom name.
To get the details of this channel: https://www.youtube.com/user/thenewboston, for example, the request would be:
GET https://www.googleapis.com/youtube/v3/channels?part=snippet&forUsername=thenewboston&key={YOUR_API_KEY}
Response
200
- SHOW HEADERS -
{
"kind": "youtube#channelListResponse",
"etag": "\"zekp1FB4kTkkM-rWc1qIAAt-BWc/8Dz6-vPu69KX3yZxVCT3-M9YWQA\"",
"pageInfo": {
"totalResults": 1,
"resultsPerPage": 5
},
"items": [
{
"kind": "youtube#channel",
"etag": "\"zekp1FB4kTkkM-rWc1qIAAt-BWc/KlQLDlUPRAmACwKt9V8V2yrOfEg\"",
"id": "UCJbPGzawDH1njbqV-D5HqKw",
"snippet": {
"title": "thenewboston",
"description": "Tons of sweet computer related tutorials and some other awesome videos too!",
"publishedAt": "2008-02-04T16:09:31.000Z",
"thumbnails": {
"default": {
"url": "https://yt3.ggpht.com/--n5ELY2uT-U/AAAAAAAAAAI/AAAAAAAAAAA/d9JvaIEpstw/s88-c-k-no-rj-c0xffffff/photo.jpg"
},
"medium": {
"url": "https://yt3.ggpht.com/--n5ELY2uT-U/AAAAAAAAAAI/AAAAAAAAAAA/d9JvaIEpstw/s240-c-k-no-rj-c0xffffff/photo.jpg"
},
"high": {
"url": "https://yt3.ggpht.com/--n5ELY2uT-U/AAAAAAAAAAI/AAAAAAAAAAA/d9JvaIEpstw/s240-c-k-no-rj-c0xffffff/photo.jpg"
}
},
"localized": {
"title": "thenewboston",
"description": "Tons of sweet computer related tutorials and some other awesome videos too!"
}
}
}
]
}
It works perfectly.
Now we have to get details of these channels:
https://www.youtube.com/c/eretteretlenek
https://www.youtube.com/c/annacavalli
Then we get:
GET https://www.googleapis.com/youtube/v3/channels?part=snippet&forUsername=annacavalli&key={YOUR_API_KEY}
Response
200
- SHOW HEADERS -
{
"kind": "youtube#channelListResponse",
"etag": "\"zekp1FB4kTkkM-rWc1qIAAt-BWc/TAiG4jjJ-NTZu7gPKn7WGmuaZb8\"",
"pageInfo": {
"totalResults": 0,
"resultsPerPage": 5
},
"items": [
]
}
This can be easily reproduced using the API explorer.
Simplest solution, using API only, is to just use Search:list method of YouTube Data API. From what I can tell (mind you, this is from my own research, official docs say nothing on this subject!), if you search using the custom URL component, with "channel" result type filter and "relevance" (default) sorting, first result should be what you're looking for.
So the following query gets 16 results, with the first one being the one you're looking for. Same goes for all other custom channel URLs I tested, so I think this is the most reliable way of doing this.
GET https://www.googleapis.com/youtube/v3/search?part=id%2Csnippet&q=annacavalli&type=channel&key={YOUR_API_KEY}
The other idea is just scraping YouTube page at the custom URL, where you can find ChannelID in one of the meta tags in HTML code. But that's ineffective, unreliable and AFAIK in violation of YouTube terms of use.
Edit: Well, it returns no results for smaller channels, so it's not reliable at all.
Workaround
Expanding off of #jkondratowicz answer, using the search.list in combination with channels.list you can most of the time resolve the channel from the custom url value.
The channel resource has a property customUrl so if we take the channels from the search.list results and get that extra detail about them from the channels.list it is possible to try and match up the custom url value with the customUrl property.
A working JavaScript method here, just replace the api key with your own. Though it is still not perfect, this tries the first 50 channels returned. More could be done with paging and pageTokens.
function getChannel(customValue, callback) {
const API_KEY = "your_api_key"
$.ajax({
dataType: "json",
type: "GET",
url: "https://www.googleapis.com/youtube/v3/search",
data: {
key: API_KEY,
part: "snippet",
q: customValue,
maxResults: 50,
order: 'relevance',
type: 'channel'
}
}).done(function (res) {
const channelIds = [];
for (let i=0; i<res.items.length; i++) {
channelIds.push(res.items[i].id.channelId);
}
$.ajax({
dataType: "json",
type: "GET",
url: "https://www.googleapis.com/youtube/v3/channels",
data: {
key: API_KEY,
part: "snippet",
id: channelIds.join(","),
maxResults: 50
}
}).done(function (res) {
if (res.items) {
for (let i=0; i<res.items.length; i++) {
const item = res.items[i];
if (item.snippet.hasOwnProperty("customUrl") && customValue.toLowerCase() === item.snippet.customUrl.toLowerCase()) {
callback(item);
}
}
}
}).fail(function (err) {
logger.err(err);
});
}).fail(function (err) {
logger.err(err);
});
}
A good example using it with https://www.youtube.com/c/creatoracademy.
getChannel('creatoracademy', function (channel) {
console.log(channel);
});
However, it is still unreliable as it depends on if the channel comes back in the original search.list query. It seems possible that if the custom channel url is too generic that the actual channel may not come back in the search.list results. Though this method is much more reliable then depending on the first entry of search.list to be the right one as search results don't always come back in the same order.
Issue
There has been at least three feature requests to Google in the past year requesting for an additional parameter for this custom url value but they were all denied as being infeasible. Apparently it is too difficult to implement. It was also mentioned as not being on their roadmap.
https://issuetracker.google.com/issues/174903934 (Dec 2020)
https://issuetracker.google.com/issues/165676622 (Aug 2020)
https://issuetracker.google.com/issues/161718177 (Jul 2020)
Resources
Google: Understand your channel URLs
Search: list | YouTube Data API
Channels: list | YouTube Data API
An alternative way is to use a parser (PHP Simple HTLM DOM parser, for the example below : PHP Simple HTML DOM Parser) :
<?php
$media_url = 'https://www.youtube.com/c/[Channel name]';
$dom = new simple_html_dom();
$html = $dom->load(curl_get($media_url));
if (null !== ($html->find('meta[itemprop=channelId]',0))) {
$channelId = $html->find('meta[itemprop=channelId]',0)->content;
}
?>
(Using Youtube api's "search" method has a quota cost of 100)
It is possible the get the channel ID by the video ID, that can help depends on the need fo your application.
Here are an example:
$queryParams = [
'id' => 'UcDjWCEvZLM'
];
$response = $service->videos->listVideos('snippet', $queryParams)->getItems();
$channelId = $response[0]->snippet['channelId'];
$channelTitle = $response[0]->snippet['channelTitle'];
I'm assuming that only channels with videos uploaded by the channel owner will be of interest. This is accidentally convenient since my method doesn't work with 0 video channels anyway.
Given a channel's url, my method will get the beautifulsoup HTML object of that channel's videos tab, and scrape the HTML to find the unique channel id. It'll then reconstruct everything and give back the channel url with the unique channel id.
your_channel_url = 'Enter your channel url here'
channel_url = your_channel_url.strip("https://").strip("featured")
https = "https://"
channel_vids_tab = https + channel_url + '/videos'
import requests
from bs4 import BeautifulSoup
source = requests.get(channel_vids_tab).text
soup = BeautifulSoup(source, "html.parser")
a = soup.find('body').find('link')['href']
channel_id = a.split('/')[-1]
print(a)
print(channel_id)
This method bypass the headache of one channel having different /user and /c url (for example /user/vechz and /c/vechz vs /c/coreyms and /user/schafer5 leading to the same page). Though you need to manually enter the url at first, it can be easily automated.
I'm also fairly confident that if a channel has 0 videos, this line of thinking can also apply for the playlist created BY the channel owner, and only needs a little tweaking. But if there's 0 videos or playlist created by the channel ... who knows
As #jkondratowicz noted, there is no way to reliably get this from the API as small channels do not return at the top of the search results.
So here is a JS example of how to get the channel id by extracting it from the HTML channel page (h/t #Feign'):
export const getChannelIdForCustomUrl = async (customUrl: string) => {
const page = await axios.get(`https://www.youtube.com/c/${customUrl}`)
const chanId = page.data.match(/channelId":"(.*?)"/)[1]
return chanId
}
Here is the .NET approach to convert custom Channel name/URL to a ChannelId using search API as mentioned in the accepted answer.
// https://www.youtube.com/c/TheQ_original/videos
// they call custom URL ?
// https://stackoverflow.com/questions/37267324/how-to-get-youtube-channel-details-using-youtube-data-api-if-channel-has-custom
// https://developers.google.com/youtube/v3/docs/channels#snippet.customUrl
// GET https://www.googleapis.com/youtube/v3/search?part=id%2Csnippet&q=annacavalli&type=channel&key={YOUR_API_KEY}
//
/// <summary>
/// Returns ChannelID from old "Custom Channel Name/URL"
/// Support the following URLs format
/// https://www.youtube.com/c/MakeYourOWNCreation
/// </summary>
/// <param name="ChannelName"></param>
/// <returns></returns>
// 20220701
public async Task<string> CustomChannelNameToChannelId(String ChannelName)
{
var YoutubeService = YouTubeService();
//
List<YouTubeInfo> VideoInfos = new List<YouTubeInfo>();
//
// -) Step1: Retrieve 1st page of channels info
var SearchListRequest = YoutubeService.Search.List("snippet");
SearchListRequest.Q = ChannelName;
SearchListRequest.Type = "channel";
//
SearchListRequest.MaxResults = 50;
// Call the search.list method to retrieve results matching the specified query term.
var SearchListResponse = await SearchListRequest.ExecuteAsync();
// According to the SO post the custom channel will be the first one
var searchResult = SearchListResponse.Items[0];
//
// Return Channel Information, we care to obtain ChannelID
return searchResult.Id.ChannelId;
}
I'm trying to use the Youtube Analytics API to gather daily view counts for all the videos in my channel. It seems like the video dimension throttles the result at top 10 only. Is there anyway I could get daily view count for all my videos?
At the moment you cannot get metrics for all videos via Analytics API directly. First you need to fetch the ids of all your videos and then request Analytic's data for each. I managed it this way:
Get the playlist ID for your uploaded videos via Data API https://www.googleapis.com/youtube/v3/channels?part=contentDetails&mine=true&maxResults=25&access_token=[TOKEN]. Gives you this result:
{
"kind": "youtube#channelListResponse",
"etag": "\"F9iA7pnxqNgrkOutjQAa9F2k8HY/SAGx1pv6myGXge51dmywGW81h8o\"",
"pageInfo": {
"totalResults": 1,
"resultsPerPage": 1
},
"items": [
{
"kind": "youtube#channel",
"etag": "\"F9iA7pnxqNgrkOutjQAa9F2k8HY/g5zJtodBJms3CAfwF_ar2nVgJjU\"",
"id": "[id]",
"contentDetails": {
"relatedPlaylists": {
"likes": "[id]",
"favorites": "[id]",
"uploads": "[id]",
"watchHistory": "[id]",
"watchLater": "[id]"
},
"googlePlusUserId": "[id]"
}
}
]
}
Get all ids of your uploaded videos with the upload playlist id via Data API: https://www.googleapis.com/youtube/v3/playlistItems?part=id&pageToken=&playlistId=[UPLOADID]&maxResults=50&access_token=[TOKEN]. Note: You have to page through the results with nextPageToken.
With the collected video ids you can make a batch request to the Analytics API https://www.googleapis.com/youtube/analytics/v1/reports?ids=channel==mine&start-date=2014-12-29&end-date=2015-01-05&metrics=views,likes&dimensions=video,day&filters=video==[videoId],[videoId],[videoId],[...]&sort=video&access_token=[TOKEN] Note: You can batch up to 200 Video Ids.