I'm trying to download captions from some videos on Youtube using their nuget package. Here's some code:
var request = _youtube.Search.List("snippet,id");
request.Q = "Bill Gates";
request.MaxResults = 50;
request.Type = "video";
var results = request.Execute();
foreach (var result in results.Items)
{
var captionListRequest = _youtube.Captions.List("id,snippet", result.Id.VideoId);
var captionListResponse = captionListRequest.Execute();
var russianCaptions =
captionListResponse.Items.FirstOrDefault(c => c.Snippet.Language.ToLower() == "ru");
if (russianCaptions != null)
{
var downloadRequest = _youtube.Captions.Download(russianCaptions.Id);
downloadRequest.Tfmt = CaptionsResource.DownloadRequest.TfmtEnum.Srt;
var ms = new MemoryStream();
downloadRequest.Download(ms);
}
}
When the Download method is called I'm getting a weird Newtonsoft.JSON Exception that says:
Newtonsoft.Json.JsonReaderException: 'Unexpected character encountered while parsing value: T. Path '', line 0, position 0.'
at Newtonsoft.Json.JsonTextReader.ParseValue()
I've read some other threads on captions downloading problems and have tried to change my authorization workflow: first I've tried to use just the ApiKey but then also tried OAuth. Here's how it looks now:
var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
new ClientSecrets
{
ClientId = "CLIENT_ID",
ClientSecret = "CLIENT_SECRET"
},
new[] { YouTubeService.Scope.YoutubeForceSsl },
"user",
CancellationToken.None,
new FileDataStore("Youtube.CaptionsCrawler")).Result;
_youtube = new YouTubeService(new BaseClientService.Initializer
{
ApplicationName = "LKS Captions downloader",
HttpClientInitializer = credential
});
So, is it even possible to do what I'm trying to achieve?
P.S. I was able to dig deep into the youtube nuget package and as I see, the actual message, that I get (that Newtonsoft.JSON is trying to deserialize, huh!) is "The permissions associated with the request are not sufficient to download the caption track. The request might not be properly authorized, or the video order might not have enabled third-party contributions for this caption."
So, do I have to be the video owner to download captions? But if so, how do other programs like Google2SRT work?
Found this post How to get "transcript" in youtube-api v3
You can get them via GET request on: http://video.google.com/timedtext?lang={LANG}&v={VIDEOID}
Example:
http://video.google.com/timedtext?lang=en&v=-osCkzoL53U
Note that they should have subtitles added, will not work if auto-generated.
Related
using (var stream = new FileStream("C:/textToSpeech/client_secret.json", FileMode.Open, FileAccess.Read))
{
var credential = GoogleCredential.FromStream(stream).CreateScoped(LoggingServiceV2Client.DefaultScopes);
var channel = new Grpc.Core.Channel(
LoggingServiceV2Client.DefaultEndpoint.ToString(),
credential.ToChannelCredentials());
var client = await TextToSpeechClient.CreateAsync(channel.ShutdownToken);
//var client = TextToSpeechClient.Create();
var input = new SynthesisInput
{
Text = "This is Demo of the Google Cloud Text-to-Speech API"
};
VoiceSelectionParams voiceSelection = new VoiceSelectionParams
{
LanguageCode = "en-US",
SsmlGender = SsmlVoiceGender.Female,
};
var audioConfig = new AudioConfig
{
AudioEncoding = AudioEncoding.Mp3
};
var response = client.SynthesizeSpeech(input, voiceSelection, audioConfig);
using (var output = File.Create("output.mp3"))
{
response.AudioContent.WriteTo(output);
}
Console.WriteLine("Audio content written to file output.mp3");
}
I want to convert my text to audio text in a form application but I get an error while translating. I signed up for Google Cloud Platform and created my JSON file by doing the necessary actions. I am getting the following error while authorizing the API.You can see the screenshot of the error I got here. I added the necessary things to the environment variables. I tried every solution I found on the internet, but I could not get rid of this error. Error => System.InvalidOperationException: 'Error creating credential from JSON. Unrecognized credential type .'
I've been scouring the internet for a few hours trying to figure out what is necessary to upload a file that will be contained within a Team Drive.
I've read most of the documentation, the only interesting bits / mention of team drives I found are here, but unfortunately there's no specifics:
https://developers.google.com/drive/v3/web/manage-uploads
https://developers.google.com/drive/v3/web/manage-teamdrives
https://developers.google.com/drive/v3/web/about-files
I'm using the .Net gapi nuget package (v3). Create a service like the following:
string[] scopes = new string[] { DriveService.Scope.Drive, DriveService.Scope.DriveFile };
var secrets = new ClientSecrets
{
ClientId = "...",
ClientSecret = "...",
};
var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(secrets, scopes, Environment.UserName, CancellationToken.None).Result;
var service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "...",
});
I have the Id of the Team Drive I'm targetting, and I can successfully retrieve the TeamDrive by the following code, but there are no interesting methods here for uploading:
var teamDrive = service.Teamdrives.Get(driveFolderId).Execute();
I've currently been trying to use the normal CreateMediaUpload way of creating a file.
File body = new File();
body.Name = name;
body.MimeType = "application/octet-stream";
FilesResource.CreateMediaUpload request = service.Files.Create(body, stream, "text/plain");
request.Upload();
There's a few interesting properties on File, namely Parents and also TeamDriveId. When setting the TeamDriveId to the Team Drive Id, the file ends up in my personal drive in the root directory. When setting the parent to the Team Drive Id, I can't seem to find the file anywhere.
There are no errors thrown, and the result of request.Upload() indicates Success/Complete every time (even if the file doesn't show up). Where else should I be looking to set the parent team drive? There's no other interesting properties on File, DriveService, or TeamDrive so I'm pretty lost.
In addition to setting to the parent to the team drive id, you must also set the SupportsTeamDrives property to true in the request.
The code would then look similar to the following (I've noted the important lines):
File body = new File();
body.Name = name;
body.MimeType = "application/octet-stream";
body.Parents = new List<string> { driveFolderId }; // <--------
FilesResource.CreateMediaUpload request = service.Files.Create(body, stream, "application/octet-stream");
request.SupportsTeamDrives = true; // <--------
request.Upload();
The key here is that the Team Drives permission scheme is completely different to the personal drive permission scheme, so you need to explicitly opt-in to it to prove you understand the differences.
An extra bit of info, if you want to list or search for files in a team drive, you must also specify IncludeTeamDriveItems and Corpora on the request (in addition to SupportsTeamDrives).
A Search might then look like this
var existingSearch = service.Files.List();
existingSearch.Fields = "nextPageToken, files(id, name)";
existingSearch.Q = $"'{driveFolderId}' in parents and name = '{name}'";
if (isFolderTeamDrive)
{
existingSearch.SupportsTeamDrives = true;
existingSearch.Corpora = "teamDrive";
existingSearch.IncludeTeamDriveItems = true;
existingSearch.TeamDriveId = driveFolderId;
}
var existingResponse = existingSearch.Execute();
I am trying to broadcast live from my .Net application using Youtube.Data.Api v3.
I have set up OAuth and downloaded the .JSON file, and that works fine. I know that, because I have already successfully obtained a list of channels resp. videos on my account, i.e., following code works:
var channelsRequest = ytService.Channels.List("contentDetails, snippet");
channelsRequest.Mine = true;
var channelsListResponse = channelsRequest.Execute();
But if I try to execute a insert request (for completeness I show you the whole method),
public static LiveBroadcast CreateImmediateBroadcast(string title = "DefaultBroadcast") {
var snippet = new LiveBroadcastSnippet();
snippet.Title = title;
snippet.ScheduledStartTime = DateTime.Now;
snippet.ScheduledEndTime = DateTime.Now + TimeSpan.FromMinutes(60);
var status = new LiveBroadcastStatus();
status.PrivacyStatus = "unlisted";
var broadcast = new LiveBroadcast();
broadcast.Kind = "youtube#liveBroadcast";
broadcast.Snippet = snippet;
broadcast.Status = status;
var insertBroadcastRequest = ytService.LiveBroadcasts.Insert(broadcast, "snippet, status");
insertBroadcastRequest.Execute();
return broadcast;
}
I get an exception when calling insertBroadcastRequest.Execute(), namely:
Google.GoogleApiException was unhandled
HResult=-2146233088
Message=Google.Apis.Requests.RequestError
Insufficient Permission [403]
Errors [
Message[Insufficient Permission] Location[ - ] Reason[insufficientPermissions] Domain[global]
]
ServiceName=youtube
Source=Google.Apis
StackTrace:
at Google.Apis.Requests.ClientServiceRequest`1.Execute() in C:\Users\cloudsharp\Documents\GitHub\google-api-dotnet-client\Src\Support\GoogleApis\Apis\Requests\ClientServiceRequest.cs:line 96
at YoutubeConsole.YouTubeAPI.CreateImmediateStream(String title) in C:\Users\bussg\Source\Workspaces\OwnExperimental\YoutubeConsole\YoutubeConsole\YouTubeAPI.cs:line 87
at YoutubeConsole.YouTubeAPI.Test() in
...
Also, for completeness, here is my authorization,
using (var stream = new FileStream(Directory.GetCurrentDirectory() + #"\GoogleAuthOtherApplication.json", FileMode.Open, FileAccess.Read)) {
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
new[] { YouTubeService.Scope.YoutubeForceSsl},
"user",
CancellationToken.None,
new FileDataStore("YouTubeAPI")
).Result;
}
Also, For the YouTubeService.Scope I have tried all options. The insert method should work with ForceSsl according to the documentation.
Also this documentation page sais
Note: A channel must be approved to use the YouTube Live feature, which enables the channel owner to stream live content to that channel. If you send API requests on behalf of an authenticated user whose channel is not enabled or eligible to stream live content, the API will return an insufficientPermissions error.
But all my channels are approved for Youtube Live. Any ideas how to get this to work?
Ok after some testing between us over Email.
You need to have the correct scope "YouTubeService.Scope.YoutubeForceSsl" by changing "user" we forced it to request permissions again. My tutorial on how filedata store works in the Google .net client library
remove the space "snippet, status" by sending "snippet,status" it worked for me.
For the fun of it: Issue 8568:LiveBroadcasts: insert - spaces in part
I am trying to download the most recent items from a YouTube playlist in a C# .NET program. Right now I have a program that successfully gets the necessary data from my channel's Uploads playlist using "channel.ContentDetails.RelatedPlaylists.Uploads;", which I got from the sample program on the API page. But I can't find any information in the api docs about how to switch that line or lines around it to get a playlist by ID rather than my own uploads.
This is not a duplicate because other examples on this page explain how to find it through an http link, as in "http://gdata.youtube.com/feeds/api/playlists/..." etc. I want to do it directly through the API's methods. The part of my code that downloads the data is included below.
private async Task Run()
{
var youtubeService = new YouTubeService(new BaseClientService.Initializer()
{
ApiKey = "API KEY HERE",
ApplicationName = this.GetType().ToString()
});
//MAYBE I NEED TO CHANGE THIS? SOMETHING LIKE
//'youtubeservice.Playlists.IDUNNOWHAT'
var channelsListRequest = youtubeService.Channels.List("contentDetails");
channelsListRequest.Id = "CHANNEL ID HERE";
// Retrieve the contentDetails part of the channel resource for the authenticated user's channel.
var channelsListResponse = await channelsListRequest.ExecuteAsync();
foreach (var channel in channelsListResponse.Items)
{
//OR MAYBE I NEED TO CHANGE THIS PART?
//LIKE 'channel.ContentDetails.SOMETHING
var uploadsListId = channel.ContentDetails.RelatedPlaylists.Uploads;
var nextPageToken = "";
while (nextPageToken != null)
{
var playlistItemsListRequest = youtubeService.PlaylistItems.List("snippet");
playlistItemsListRequest.PlaylistId = uploadsListId;
playlistItemsListRequest.MaxResults = 50;
playlistItemsListRequest.PageToken = nextPageToken;
// Retrieve the list of videos uploaded to the authenticated user's channel.
var playlistItemsListResponse = await playlistItemsListRequest.ExecuteAsync();
/*
* DO A BUNCH OF STUFF WITH THE YOUTUBE DATA
*/
nextPageToken = playlistItemsListResponse.NextPageToken;
}
}
}
In the documentation, it lists the playlists you can get by using ContentDetails.RelatedPlaylists:
likes
favorites
uploads
watchHistory
watchLater
Therefore, if you want to get the items for a playlist you created you won't be able to do it using ContentDetails.RelatedPlaylists, you'll have to provide the playlist ID. I believe it should work with the code you provided (might need a few tweaks) if you change
playlistItemsListRequest.PlaylistId = uploadsListId;
to use the ID of the playlist whose videos you want to get.
I'm trying to delete one or more videos using a simple C# app (I intend to use a Windows Service later) and I'm getting this error:
Google.Apis.Auth.OAuth2.Responses.TokenResponseException: Error:"unauthorized_client", Description:"Unauthorized client or scope in request.", Uri:""
at Google.Apis.Requests.ClientServiceRequest`1.Execute() in c:\code\google.com\google-api-dotnet-client\default\Tools\Google.Apis.Release\bin\Debug\test\default\Src\GoogleApis\Apis\Requests\ClientServiceRequest.cs:line 93
Uploading videos works perfectly. For both operations, I use the same initialization method:
private static YouTubeService AuthorizeYoutubeService()
{
string serviceAccountEmail = "...#developer.gserviceaccount.com";
string keyFilePath = "Warehouse<...>.p12";
string userAccountEmail = "login#gmail.com";
if (!File.Exists(keyFilePath))
{
System.Windows.Forms.MessageBox.Show("Secret file not found!");
return null;
}
var scope = new string[] { YouTubeService.Scope.Youtube };
var cert = new X509Certificate2(keyFilePath, "notasecret", X509KeyStorageFlags.Exportable);
try
{
ServiceAccountCredential credential = new ServiceAccountCredential
(new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = scope,
User = userAccountEmail
}.FromCertificate(cert));
var service = new YouTubeService(new BaseClientService.Initializer
{
HttpClientInitializer = credential,
ApplicationName = "warehouse"
});
return service;
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
return null;
}
}
The difference compared to simply uploading videos, is the defined Scope: YouTubeService.Scope.YoutubeUpload. When I try to delete a video using it, I get an insufficientPermissions (403) error.
So after looking in the documentation I've changed it to YouTubeService.Scope.Youtube.
Here's the code I'm trying to use:
var youtubeService = AuthorizeYoutubeService();
foreach (string id in deleteIds)
{
var videoDeleteRequest = youtubeService.Videos.Delete(id);
var result = videoDeleteRequest.Execute();
}
Where deleteIds is a list of 11 character strings containing IDs of existing videos.
I have YouTube Data API enabled in the developers console.
I've installed the API via NuGet, I don't think there's anything wrong with the packages.
I'm quite new to Google development, and all similar questions were about the calendar API.
I appreciate any help.
What I ended up doing is reseting the list of apps connected to the Google account and setting it up again from scratch. My app was added 2 times for some reason.