终于破解了!
现在,所以你不必经历我所经历的同样的盲目试验和恐怖经历:
using Google.GData.Client;
using Google.GData.YouTube;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
using System.Xml;
...
YouTubeService service = new YouTubeService("YouTube API Client", Properties.Settings.Default.YouTubeDeveloperKey);
const String searchFields = "entry(id,title,link[@rel='alternate'],author(name,yt:userId),media:group(media:category(@label),media:credit,yt:videoid,yt:uploaderId),yt:statistics,yt:rating,gd:rating(@average),gd:comments/gd:feedLink(@countHint))";
String urlBase = String.Format("https://{0}gdata.youtube.com/feeds/api/videos", (testing ? "stage." : ""));
String url = String.Format("{0}?v=2&fields={1}", urlBase, searchFields);
Debug.Print(url);
YouTubeQuery searchQuery = new YouTubeQuery(url);
searchQuery.Query = keyword;
searchQuery.NumberToRetrieve = Properties.Settings.Default.NumVideosToRetrieve;
searchQuery.OrderBy = "relevance";
lblTagStats.Text = "Retrieving Top " + searchQuery.NumberToRetrieve + " Videos...";
YouTubeFeed searchResults = service.Query(searchQuery);
DebugSaveToXml(searchResults, "searchResults");
foreach (YouTubeEntry entry in searchResults.Entries)
{
titles.Add(entry.Title.Text);
if (entry.Statistics != null)
viewCounts.Add(long.Parse(entry.Statistics.ViewCount));
if (entry.Comments != null)
commentCounts.Add(long.Parse(entry.Comments.FeedLink.CountHint.ToString()));
if (entry.Rating != null)
ratings.Add(entry.Rating.Average);
if (entry.YtRating != null)
{
likeCounts.Add(long.Parse(entry.YtRating.NumLikes));
dislikeCounts.Add(long.Parse(entry.YtRating.NumDislikes));
}
videoURLs.Add(new Uri(entry.AlternateUri.ToString()));
uploaders.Add(entry.Authors[0].Name);
foreach (var category in entry.Media.Categories)
if (category.Attributes["label"] != null)
categories.Add(category.Attributes["label"].ToString());
}
lblTagStats.Text = "Retrieving Subscriber Counts...";
AtomFeed batchRequest = new AtomFeed(searchResults);
batchRequest.BatchData = new GDataBatchFeedData();
batchRequest.BatchData.Type = GDataBatchOperationType.query;
foreach (YouTubeEntry entry in searchResults.Entries)
{
AtomEntry batchEntry = searchResults.CreateFeedEntry();
String uploaderId = entry.Media.ChildNodes.Find(x => x.Name == "yt:uploaderId").InnerText;
batchEntry.Id = new AtomId("tag:youtube.com,2008:user:" + uploaderId); //not returned in search, so reconstruct it
batchEntry.BatchData = new GDataBatchEntryData();
urlBase = String.Format("https://{0}gdata.youtube.com/feeds/api/users", (testing ? "stage." : ""));
url = String.Format("{0}/{1}?v=2", urlBase, entry.Media.Credit.Value);
Debug.Print(url);
batchEntry.EditUri = url;
batchRequest.Entries.Add(batchEntry);
}
DebugSaveToXml(batchRequest, "batchRequest_Profiles");
const String profileFields = ""; // "&fields=id,yt:username,yt:statistics(@subscriberCount)"; // YouTube API bug: cant handle colons in batch request fields
urlBase = String.Format("https://{0}gdata.youtube.com/feeds/api/users/batch", (testing ? "stage." : ""));
url = String.Format("{0}?v=2{1}", urlBase, profileFields);
Debug.Print(url);
YouTubeFeed profilesFeed = (YouTubeFeed)service.Batch(batchRequest, new Uri(url));
DebugSaveToXml(profilesFeed,"profilesFeed");
foreach (ProfileEntry entry in profilesFeed.Entries)
if (entry.BatchData.Status.Code == 200)
subscriberCounts.Add(long.Parse(entry.Statistics.SubscriberCount));
lblTagStats.Text = "Retrieving Full Descriptions...";
batchRequest = new AtomFeed(searchResults);
batchRequest.BatchData = new GDataBatchFeedData();
batchRequest.BatchData.Type = GDataBatchOperationType.query;
foreach (YouTubeEntry entry in searchResults.Entries)
{
AtomEntry batchEntry = searchResults.CreateFeedEntry();
batchEntry.Id = entry.Id;
batchEntry.BatchData = new GDataBatchEntryData();
urlBase = String.Format("https://{0}gdata.youtube.com/feeds/api/videos", (testing ? "stage." : ""));
url = String.Format("{0}/{1}?v=2", urlBase, entry.VideoId);
Debug.Print(url);
batchEntry.EditUri = url;
batchRequest.Entries.Add(batchEntry);
}
DebugSaveToXml(batchRequest, "batchRequest_Descriptions");
const String descriptionFields = ""; // "&fields=media:group/media:description"; // YouTube API bug: cant handle colons in batch request fields
urlBase = String.Format("https://{0}gdata.youtube.com/feeds/api/videos/batch", (testing ? "stage.":""));
url = String.Format("{0}?v=2{1}", urlBase, descriptionFields);
Debug.Print(url);
YouTubeFeed descriptionsFeed = (YouTubeFeed)service.Batch(batchRequest, new Uri(url));
DebugSaveToXml(descriptionsFeed,"descriptionsFeed");
foreach (YouTubeEntry entry in descriptionsFeed.Entries)
if (entry.BatchData.Status.Code == 200)
descriptions.Add(entry.Media.Description.Value);
仅供参考,这为配置文件发布了以下批处理请求 XML,这与其他示例有很大不同,但仍然像魅力一样工作:
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:batch="http://schemas.google.com/gdata/batch">
<link rel="http://schemas.google.com/g/2005#batch" type="application/atom+xml" />
<link rel="http://schemas.google.com/g/2005#post" type="application/atom+xml" />
<link rel="self" type="application/atom+xml" />
<link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" />
<batch:operation type="query" />
<entry xmlns:gd="http://schemas.google.com/g/2005">
<id>tag:youtube.com,2008:user:UC7UgD2HIyslGofSyX811fsQ</id>
<link href="https://stage.gdata.youtube.com/feeds/api/users/inspiredtennis?v=2" rel="edit" type="application/atom+xml" />
</entry>
<entry xmlns:gd="http://schemas.google.com/g/2005">
<id>tag:youtube.com,2008:user:UClXdxsQW4AqykIq2Fu4YXvQ</id>
<link href="https://stage.gdata.youtube.com/feeds/api/users/azishertanto?v=2" rel="edit" type="application/atom+xml" />
</entry>
<entry xmlns:gd="http://schemas.google.com/g/2005">
<id>tag:youtube.com,2008:user:UC1Diq4duvGuTUaGxk61-LOQ</id>
<link href="https://stage.gdata.youtube.com/feeds/api/users/atamaiidotcom?v=2" rel="edit" type="application/atom+xml" />
</entry>
...
</feed>