如何使用 media.download 下载 YouTube 报告
How to download YouTube report using media.download
我正在寻找一个示例,该示例解释了如何使用 YouTube 报告的 .Net 客户端库下载报告 API。我已经通过身份验证、创建了作业并检索了包含 reportUrl 值的报告列表。我不知道如何使用 media.download 方法实际下载报告并将其保存在本地。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Threading; //CancelationToken
using Google.Apis;
using Google.Apis.Auth.OAuth2;
using Google.Apis.YouTubeReporting.v1; //Scope of auth
using Google.Apis.YouTubeReporting.v1.Data;
using Google.Apis.Services;
using Google.Apis.Util.Store; //FileDataStore needs this
using System.Data.SqlClient;
namespace YouTubeReportingConsole
{
class Program
{
static void Main(string[] args)
{
//Console.WriteLine("Number of command line parameters = {0}", args.Length);
//for (int i = 0; i < args.Length; i++)
//{
// Console.WriteLine("Arg[{0}] = [{1}]", i, args[i]);
//}
if (args.Length > 0)
{
switch (args[0].ToLower())
{
case "reporttypeslist": //ReportTypesList returns a list of report types that are available
ListReportTypesResponse reportTypesListResponse = ytReportingService.ReportTypes.List().Execute();
foreach (ReportType reportType in reportTypesListResponse.ReportTypes)
{
WriteReportType(reportType, "Report Type List");
}
break;
case "jobcreate": //JobCreate creates jobs of the specified types. If the second argument equals "All", then a job is created for all availale report types.
for (int i = 1; i < args.Length; i++)
{
if (args[i].ToLower() == "all")
{ //Create a job for all available report types
ListReportTypesResponse reportTypesAvailableResponse = ytReportingService.ReportTypes.List().Execute();
foreach (ReportType reportType in reportTypesAvailableResponse.ReportTypes)
{
Job createdjob = CreateJob(reportType.Id);
WriteJob(createdjob, "Job Created");
}
break;
}
else
{ //Create job with id equal to the argument value
Job createdjob = CreateJob(args[i].ToLower());
WriteJob(createdjob, "Job Created");
}
}
break;
case "jobdelete":
for (int i = 1; i < args.Length; i++)
{
if (args[i].ToLower() == "all")
{ //Delete all jobs
ListJobsResponse jobDeleteList = ytReportingService.Jobs.List().Execute();
foreach (Job Job in jobDeleteList.Jobs)
{
ytReportingService.Jobs.Delete(Job.Id).Execute();
Console.WriteLine("Job Deleted: " + Job.Name);
}
break;
}
else
{ //Delete each job with id equal to the argument value
Job Job = ytReportingService.Jobs.Get(args[i]).Execute();
ytReportingService.Jobs.Delete(args[i]).Execute();
Console.WriteLine("Job Deleted: " + Job.Name);
}
}
break;
//case "getjob":
// break;
case "joblist":
ListJobsResponse jobListResponse = ytReportingService.Jobs.List().Execute();
if (jobListResponse.Jobs == null)
{
Console.WriteLine("No Jobs Returned");
}
else
{
foreach (Job Job in jobListResponse.Jobs)
{
WriteJob(Job, "Job List");
}
}
break;
//case "getreport":
// break;
case "reportlist":
//ReportList All [DataSource]
//ReportList [JobID] [DataSource]
//ReportList All [DataSource] [DownloadPath]
//ReportList [JobID] [DataSource] [DownloadPath]
SqlConnection conn = OpenConnection(args[2]);
VerifySchema(conn);
if (args[1].ToLower() == "all")
{ //List reports for all jobs
ListJobsResponse jobListResponseReport = ytReportingService.Jobs.List().Execute();
if (jobListResponseReport.Jobs == null)
{
Console.WriteLine("No Jobs Returned");
}
else
{
foreach (Job Job in jobListResponseReport.Jobs)
{
Report(Job.Id, conn, args[3]);
}
}
break;
}
else
{ //Single Job
Report(args[1], conn, args[3]);
}
break;
default:
break;
}
}
}
private static void Report(string JobId, SqlConnection conn, string path)
{
//Get the last created time. If empty then use 1900.
var reportList = ytReportingService.Jobs.Reports.List(JobId);
try
{
reportList.CreatedAfter = LastCreatedTime(conn, JobId);
}
catch
{
reportList.CreatedAfter = "1900-01-01T12:00:00.000000Z";
}
ListReportsResponse reportListResponse = reportList.Execute();
if (reportListResponse.Reports == null)
{
Console.WriteLine("No Reports for JobID: " + JobId);
}
else
{
foreach (Report report in reportListResponse.Reports)
{
//Download the report
var request = ytReportingService.Media.Download("");
//Insert report into history
string reportInsertSql = "INSERT INTO [dbo].[YouTubeReportHistory]" + "\n" +
"([reportId]" + "\n" +
",[jobId]" + "\n" +
",[startTime]" + "\n" +
",[endTime]" + "\n" +
",[createTime]" + "\n" +
",[jobExpireTime]" + "\n" +
",[downloadUrl])" + "\n" +
"VALUES" + "\n" +
"('" + report.Id + "'\n" +
",'" + JobId + "'\n" +
",'" + report.StartTime + "'\n" +
",'" + report.EndTime + "'\n" +
",'" + report.CreateTime + "'\n" +
",'" + report.JobExpireTime + "'\n" +
",'" + report.DownloadUrl + "')";
SqlCommand reportInsert = new SqlCommand(reportInsertSql, conn);
reportInsert.ExecuteNonQuery();
reportInsert.Dispose();
WriteReport(report, "Report");
}
}
}
private static string LastCreatedTime(SqlConnection conn, string JobId)
{
//*****************************************************************************************************************
//Library is not returning milliseconds. Adding 1 seconds to prevent collecting same report multiple times.
//Risk of missing report. Minimal chance that the same job will return more than one report in one second.
//*****************************************************************************************************************
SqlCommand comm = new SqlCommand("SELECT isnull(convert(varchar(50), dateadd(second, 1, max(cast([createTime] as datetimeoffset))), 127), '1900-01-01T12:00:00.000000Z') createTimeZulu FROM [dbo].[YouTubeReportHistory] where jobId = '" + JobId + "'", conn);
SqlDataReader reader = null;
reader = comm.ExecuteReader();
string LastCreatedTime = "";
if (reader.HasRows)
{
reader.Read();
LastCreatedTime = reader["createTimeZulu"].ToString();
reader.Close();
comm.Dispose();
}
else
{
LastCreatedTime = "1900-01-01T12:00:00.000000Z";
}
return LastCreatedTime;
}
//Feedback information only
private static void WriteReport(Report report, String Event)
{
// DateTime convertedDate = DateTime.SpecifyKind(DateTime.Parse(report.CreateTime.ToString()), DateTimeKind.Utc);
Console.WriteLine("================== Job Report ==================");
Console.WriteLine("Event: " + Event);
Console.WriteLine("ID: " + report.Id);
Console.WriteLine("DownloadUrl: " + report.DownloadUrl);
Console.WriteLine("CreateTime: " + report.CreateTime.ToString());
Console.WriteLine("StartTime: " + report.StartTime);
Console.WriteLine("EndTime: " + report.EndTime);
Console.WriteLine("JobID: " + report.JobId);
Console.WriteLine("JobExpireTime: " + report.JobExpireTime);
}
//Feedback information only
private static void WriteJob (Job job, String Event) {
Console.WriteLine("================== Reporting Job ==================");
Console.WriteLine("Event: " + Event);
Console.WriteLine("ID: " + job.Id);
Console.WriteLine("Name: " + job.Name);
Console.WriteLine("ReportTypeID: " + job.ReportTypeId);
Console.WriteLine("CreateTime: " + job.CreateTime);
Console.WriteLine("ExpireTime: " + job.ExpireTime);
}
//Feedback information only
private static void WriteReportType(ReportType reportType, String Event)
{
Console.WriteLine("================== Report Type ==================");
Console.WriteLine("Event: " + Event);
Console.WriteLine("ID: " + reportType.Id);
Console.WriteLine("Name: " + reportType.Name);
Console.WriteLine("SystemManaged: " + reportType.SystemManaged);
}
//Create a job
private static Job CreateJob(String ReportType)
{
Job job = new Job();
job.ReportTypeId = ReportType;
job.Name = ReportType; //Use the type as the name
Job createdjob = ytReportingService.Jobs.Create(job).Execute();
return createdjob;
}
private static String DeleteJob(String JobID)
{
ytReportingService.Jobs.Delete(JobID);
return JobID;
}
//Establish connection
private static SqlConnection OpenConnection(string connectionString)
{
//Data Source = WIN-IDD5KG7V0RT\SS2016;Integrated Security=true; Initial Catalog=Control; MultipleActiveResultSets=True;
//Database must exists
//Must have MARS = True
SqlConnection conn = new SqlConnection(connectionString);
try
{
conn.Open();
}
catch(Exception e)
{
Console.WriteLine(e.ToString());
}
return conn;
}
//Close connection
private static void CloseConnection(SqlConnection conn)
{
try
{
conn.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
//Ensure schema is in place
private static void VerifySchema(SqlConnection conn)
{
//Ensure table exists
//Ensure db exists
String tblExists = "if not exists (Select * From sys.tables where name = 'YouTubeReportHistory')" + "\n" +
"Begin" + "\n" +
"CREATE TABLE[dbo].[YouTubeReportHistory](" + "\n" +
"[id][int] IDENTITY(1, 1) NOT NULL," + "\n" +
"[loadTime] [datetime] NOT NULL," + "\n" +
"[reportId] [varchar](50) NOT NULL," + "\n" +
"[jobId] [varchar](50) NOT NULL," + "\n" +
"[startTime] [datetime] NOT NULL," + "\n" +
"[endTime] [datetime] NOT NULL," + "\n" +
"[createTime] [datetime] NOT NULL," + "\n" +
"[jobExpireTime] [datetime] NOT NULL," + "\n" +
"[downloadUrl] [varchar](1000) NOT NULL," + "\n" +
"CONSTRAINT[PK_YouTubeReportHistory] PRIMARY KEY CLUSTERED([id] ASC)" + "\n" +
")" + "\n" +
"ALTER TABLE[dbo].[YouTubeReportHistory] ADD CONSTRAINT[DF_YouTubeReportHistory_loadTime] DEFAULT(sysdatetime()) FOR[loadTime]" + "\n" +
"End";
SqlCommand comm = new SqlCommand(tblExists, conn);
comm.ExecuteNonQuery();
comm.Dispose();
}
private static YouTubeReportingService ytReportingService = Auth();
private static YouTubeReportingService Auth()
{
UserCredential creds;
using(var stream = new FileStream("client_secret.json", FileMode.Open, FileAccess.Read))
{
creds = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
new[] { YouTubeReportingService.Scope.YtAnalyticsMonetaryReadonly, YouTubeReportingService.Scope.YtAnalyticsReadonly },
"user",
CancellationToken.None,
new FileDataStore("YouTubeAPI")
).Result;
}
var service = new YouTubeReportingService(new BaseClientService.Initializer()
{
HttpClientInitializer = creds,
ApplicationName = "LeapFrogBIDataCollector"
});
return service;
}
}
}
更新20170405
我认为我遇到的问题与提供下载 URL 的方式有关。经过大量的摸索和审查我能找到的少量文档之后,我最终得到了下面的代码,这似乎是一个改进,但这仍然只有 returns headers.
MediaResource.DownloadRequest getRequest = ytReportingService.Media.Download("");
using (var fileStream = new System.IO.FileStream(@filePath + reportTypeId + "_" + report.Id + ".csv", System.IO.FileMode.Create, System.IO.FileAccess.Write))
{
// Add a handler which will be notified on progress changes.
// It will notify on each chunk download and when the download is completed or failed.
getRequest.MediaDownloader.ProgressChanged += Download_ProgressChanged;
getRequest.MediaDownloader.Download(report.DownloadUrl, fileStream);
}
20170406更新
我发现了一些其他语言的代码示例,这促使我进行了以下更改。至少下载 URL 是直接传入的,而不是我解析它并将其用作资源名称。可悲的是,我得到了相同的结果; headers 而已。没有数据。
//Download the report
MediaResource.DownloadRequest getRequest = ytReportingService.Media.Download("");
using (var fileStream = new System.IO.FileStream(@filePath + reportTypeId + "_" + report.Id + ".csv", System.IO.FileMode.Create, System.IO.FileAccess.Write))
{
// Add a handler which will be notified on progress changes. It will notify on each chunk download and when the download is completed or failed.
getRequest.MediaDownloader.ProgressChanged += Download_ProgressChanged;
getRequest.MediaDownloader.Download(report.DownloadUrl, fileStream);
}
post 示例中 media.download 的最终版本是正确的。
我在 YouTube 上有 "Brand Account"。这意味着我登录 Google 的用户有 2 "accounts"。一个帐户与 B运行d 帐户关联,另一个与我的 Google 用户关联。
我通过删除访问和刷新令牌重置了 Oath2 进程。这促使我再次允许应用程序访问请求的范围。首先,我看到一个典型的 YouTube 登录屏幕。然后,我看到一个屏幕,要求我在两个帐户之间 select;支持@leapfrogbic.om 或 LeapFrogBI。 b运行d 帐户是名为 LeapFrogBI 的帐户。
API 需要知道向应用程序发送哪个帐户 link 是有道理的。虽然这很令人困惑。 None 目前为止我找到的任何文档中都有。 F运行kly,我发现这个的唯一原因是因为我开始质疑我是否需要为 OnBehalfOfContentOwner 传递值。虽然我对命名法还不是 100% 清楚,但我想我明白是怎么回事了。
有了这些信息,我回去 运行 进行了一些测试。虽然 Oath2 被设置为使用 LeapFrogBI 帐户,但我没有收到任何工作!那是个大线索。因此,我将 Oath2 切换到 support@leapfrogbi.com 帐户,并获得了预期的工作列表。当然,所有视频都在 LeapFrogBI 帐户上,所以这可以解释为什么我在下载的报告中没有得到任何数据。
我在 LeapFrogBI 帐户上创建了报告,但报告需要 2 天才能可用。手指交叉。我希望这个问题得到解决,但我一定会让你知道无论哪种方式都会发生什么。
确认。我现在正在下载的 csv 中获取数据。
我正在寻找一个示例,该示例解释了如何使用 YouTube 报告的 .Net 客户端库下载报告 API。我已经通过身份验证、创建了作业并检索了包含 reportUrl 值的报告列表。我不知道如何使用 media.download 方法实际下载报告并将其保存在本地。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Threading; //CancelationToken
using Google.Apis;
using Google.Apis.Auth.OAuth2;
using Google.Apis.YouTubeReporting.v1; //Scope of auth
using Google.Apis.YouTubeReporting.v1.Data;
using Google.Apis.Services;
using Google.Apis.Util.Store; //FileDataStore needs this
using System.Data.SqlClient;
namespace YouTubeReportingConsole
{
class Program
{
static void Main(string[] args)
{
//Console.WriteLine("Number of command line parameters = {0}", args.Length);
//for (int i = 0; i < args.Length; i++)
//{
// Console.WriteLine("Arg[{0}] = [{1}]", i, args[i]);
//}
if (args.Length > 0)
{
switch (args[0].ToLower())
{
case "reporttypeslist": //ReportTypesList returns a list of report types that are available
ListReportTypesResponse reportTypesListResponse = ytReportingService.ReportTypes.List().Execute();
foreach (ReportType reportType in reportTypesListResponse.ReportTypes)
{
WriteReportType(reportType, "Report Type List");
}
break;
case "jobcreate": //JobCreate creates jobs of the specified types. If the second argument equals "All", then a job is created for all availale report types.
for (int i = 1; i < args.Length; i++)
{
if (args[i].ToLower() == "all")
{ //Create a job for all available report types
ListReportTypesResponse reportTypesAvailableResponse = ytReportingService.ReportTypes.List().Execute();
foreach (ReportType reportType in reportTypesAvailableResponse.ReportTypes)
{
Job createdjob = CreateJob(reportType.Id);
WriteJob(createdjob, "Job Created");
}
break;
}
else
{ //Create job with id equal to the argument value
Job createdjob = CreateJob(args[i].ToLower());
WriteJob(createdjob, "Job Created");
}
}
break;
case "jobdelete":
for (int i = 1; i < args.Length; i++)
{
if (args[i].ToLower() == "all")
{ //Delete all jobs
ListJobsResponse jobDeleteList = ytReportingService.Jobs.List().Execute();
foreach (Job Job in jobDeleteList.Jobs)
{
ytReportingService.Jobs.Delete(Job.Id).Execute();
Console.WriteLine("Job Deleted: " + Job.Name);
}
break;
}
else
{ //Delete each job with id equal to the argument value
Job Job = ytReportingService.Jobs.Get(args[i]).Execute();
ytReportingService.Jobs.Delete(args[i]).Execute();
Console.WriteLine("Job Deleted: " + Job.Name);
}
}
break;
//case "getjob":
// break;
case "joblist":
ListJobsResponse jobListResponse = ytReportingService.Jobs.List().Execute();
if (jobListResponse.Jobs == null)
{
Console.WriteLine("No Jobs Returned");
}
else
{
foreach (Job Job in jobListResponse.Jobs)
{
WriteJob(Job, "Job List");
}
}
break;
//case "getreport":
// break;
case "reportlist":
//ReportList All [DataSource]
//ReportList [JobID] [DataSource]
//ReportList All [DataSource] [DownloadPath]
//ReportList [JobID] [DataSource] [DownloadPath]
SqlConnection conn = OpenConnection(args[2]);
VerifySchema(conn);
if (args[1].ToLower() == "all")
{ //List reports for all jobs
ListJobsResponse jobListResponseReport = ytReportingService.Jobs.List().Execute();
if (jobListResponseReport.Jobs == null)
{
Console.WriteLine("No Jobs Returned");
}
else
{
foreach (Job Job in jobListResponseReport.Jobs)
{
Report(Job.Id, conn, args[3]);
}
}
break;
}
else
{ //Single Job
Report(args[1], conn, args[3]);
}
break;
default:
break;
}
}
}
private static void Report(string JobId, SqlConnection conn, string path)
{
//Get the last created time. If empty then use 1900.
var reportList = ytReportingService.Jobs.Reports.List(JobId);
try
{
reportList.CreatedAfter = LastCreatedTime(conn, JobId);
}
catch
{
reportList.CreatedAfter = "1900-01-01T12:00:00.000000Z";
}
ListReportsResponse reportListResponse = reportList.Execute();
if (reportListResponse.Reports == null)
{
Console.WriteLine("No Reports for JobID: " + JobId);
}
else
{
foreach (Report report in reportListResponse.Reports)
{
//Download the report
var request = ytReportingService.Media.Download("");
//Insert report into history
string reportInsertSql = "INSERT INTO [dbo].[YouTubeReportHistory]" + "\n" +
"([reportId]" + "\n" +
",[jobId]" + "\n" +
",[startTime]" + "\n" +
",[endTime]" + "\n" +
",[createTime]" + "\n" +
",[jobExpireTime]" + "\n" +
",[downloadUrl])" + "\n" +
"VALUES" + "\n" +
"('" + report.Id + "'\n" +
",'" + JobId + "'\n" +
",'" + report.StartTime + "'\n" +
",'" + report.EndTime + "'\n" +
",'" + report.CreateTime + "'\n" +
",'" + report.JobExpireTime + "'\n" +
",'" + report.DownloadUrl + "')";
SqlCommand reportInsert = new SqlCommand(reportInsertSql, conn);
reportInsert.ExecuteNonQuery();
reportInsert.Dispose();
WriteReport(report, "Report");
}
}
}
private static string LastCreatedTime(SqlConnection conn, string JobId)
{
//*****************************************************************************************************************
//Library is not returning milliseconds. Adding 1 seconds to prevent collecting same report multiple times.
//Risk of missing report. Minimal chance that the same job will return more than one report in one second.
//*****************************************************************************************************************
SqlCommand comm = new SqlCommand("SELECT isnull(convert(varchar(50), dateadd(second, 1, max(cast([createTime] as datetimeoffset))), 127), '1900-01-01T12:00:00.000000Z') createTimeZulu FROM [dbo].[YouTubeReportHistory] where jobId = '" + JobId + "'", conn);
SqlDataReader reader = null;
reader = comm.ExecuteReader();
string LastCreatedTime = "";
if (reader.HasRows)
{
reader.Read();
LastCreatedTime = reader["createTimeZulu"].ToString();
reader.Close();
comm.Dispose();
}
else
{
LastCreatedTime = "1900-01-01T12:00:00.000000Z";
}
return LastCreatedTime;
}
//Feedback information only
private static void WriteReport(Report report, String Event)
{
// DateTime convertedDate = DateTime.SpecifyKind(DateTime.Parse(report.CreateTime.ToString()), DateTimeKind.Utc);
Console.WriteLine("================== Job Report ==================");
Console.WriteLine("Event: " + Event);
Console.WriteLine("ID: " + report.Id);
Console.WriteLine("DownloadUrl: " + report.DownloadUrl);
Console.WriteLine("CreateTime: " + report.CreateTime.ToString());
Console.WriteLine("StartTime: " + report.StartTime);
Console.WriteLine("EndTime: " + report.EndTime);
Console.WriteLine("JobID: " + report.JobId);
Console.WriteLine("JobExpireTime: " + report.JobExpireTime);
}
//Feedback information only
private static void WriteJob (Job job, String Event) {
Console.WriteLine("================== Reporting Job ==================");
Console.WriteLine("Event: " + Event);
Console.WriteLine("ID: " + job.Id);
Console.WriteLine("Name: " + job.Name);
Console.WriteLine("ReportTypeID: " + job.ReportTypeId);
Console.WriteLine("CreateTime: " + job.CreateTime);
Console.WriteLine("ExpireTime: " + job.ExpireTime);
}
//Feedback information only
private static void WriteReportType(ReportType reportType, String Event)
{
Console.WriteLine("================== Report Type ==================");
Console.WriteLine("Event: " + Event);
Console.WriteLine("ID: " + reportType.Id);
Console.WriteLine("Name: " + reportType.Name);
Console.WriteLine("SystemManaged: " + reportType.SystemManaged);
}
//Create a job
private static Job CreateJob(String ReportType)
{
Job job = new Job();
job.ReportTypeId = ReportType;
job.Name = ReportType; //Use the type as the name
Job createdjob = ytReportingService.Jobs.Create(job).Execute();
return createdjob;
}
private static String DeleteJob(String JobID)
{
ytReportingService.Jobs.Delete(JobID);
return JobID;
}
//Establish connection
private static SqlConnection OpenConnection(string connectionString)
{
//Data Source = WIN-IDD5KG7V0RT\SS2016;Integrated Security=true; Initial Catalog=Control; MultipleActiveResultSets=True;
//Database must exists
//Must have MARS = True
SqlConnection conn = new SqlConnection(connectionString);
try
{
conn.Open();
}
catch(Exception e)
{
Console.WriteLine(e.ToString());
}
return conn;
}
//Close connection
private static void CloseConnection(SqlConnection conn)
{
try
{
conn.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
//Ensure schema is in place
private static void VerifySchema(SqlConnection conn)
{
//Ensure table exists
//Ensure db exists
String tblExists = "if not exists (Select * From sys.tables where name = 'YouTubeReportHistory')" + "\n" +
"Begin" + "\n" +
"CREATE TABLE[dbo].[YouTubeReportHistory](" + "\n" +
"[id][int] IDENTITY(1, 1) NOT NULL," + "\n" +
"[loadTime] [datetime] NOT NULL," + "\n" +
"[reportId] [varchar](50) NOT NULL," + "\n" +
"[jobId] [varchar](50) NOT NULL," + "\n" +
"[startTime] [datetime] NOT NULL," + "\n" +
"[endTime] [datetime] NOT NULL," + "\n" +
"[createTime] [datetime] NOT NULL," + "\n" +
"[jobExpireTime] [datetime] NOT NULL," + "\n" +
"[downloadUrl] [varchar](1000) NOT NULL," + "\n" +
"CONSTRAINT[PK_YouTubeReportHistory] PRIMARY KEY CLUSTERED([id] ASC)" + "\n" +
")" + "\n" +
"ALTER TABLE[dbo].[YouTubeReportHistory] ADD CONSTRAINT[DF_YouTubeReportHistory_loadTime] DEFAULT(sysdatetime()) FOR[loadTime]" + "\n" +
"End";
SqlCommand comm = new SqlCommand(tblExists, conn);
comm.ExecuteNonQuery();
comm.Dispose();
}
private static YouTubeReportingService ytReportingService = Auth();
private static YouTubeReportingService Auth()
{
UserCredential creds;
using(var stream = new FileStream("client_secret.json", FileMode.Open, FileAccess.Read))
{
creds = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
new[] { YouTubeReportingService.Scope.YtAnalyticsMonetaryReadonly, YouTubeReportingService.Scope.YtAnalyticsReadonly },
"user",
CancellationToken.None,
new FileDataStore("YouTubeAPI")
).Result;
}
var service = new YouTubeReportingService(new BaseClientService.Initializer()
{
HttpClientInitializer = creds,
ApplicationName = "LeapFrogBIDataCollector"
});
return service;
}
}
}
更新20170405
我认为我遇到的问题与提供下载 URL 的方式有关。经过大量的摸索和审查我能找到的少量文档之后,我最终得到了下面的代码,这似乎是一个改进,但这仍然只有 returns headers.
MediaResource.DownloadRequest getRequest = ytReportingService.Media.Download("");
using (var fileStream = new System.IO.FileStream(@filePath + reportTypeId + "_" + report.Id + ".csv", System.IO.FileMode.Create, System.IO.FileAccess.Write))
{
// Add a handler which will be notified on progress changes.
// It will notify on each chunk download and when the download is completed or failed.
getRequest.MediaDownloader.ProgressChanged += Download_ProgressChanged;
getRequest.MediaDownloader.Download(report.DownloadUrl, fileStream);
}
20170406更新 我发现了一些其他语言的代码示例,这促使我进行了以下更改。至少下载 URL 是直接传入的,而不是我解析它并将其用作资源名称。可悲的是,我得到了相同的结果; headers 而已。没有数据。
//Download the report
MediaResource.DownloadRequest getRequest = ytReportingService.Media.Download("");
using (var fileStream = new System.IO.FileStream(@filePath + reportTypeId + "_" + report.Id + ".csv", System.IO.FileMode.Create, System.IO.FileAccess.Write))
{
// Add a handler which will be notified on progress changes. It will notify on each chunk download and when the download is completed or failed.
getRequest.MediaDownloader.ProgressChanged += Download_ProgressChanged;
getRequest.MediaDownloader.Download(report.DownloadUrl, fileStream);
}
post 示例中 media.download 的最终版本是正确的。
我在 YouTube 上有 "Brand Account"。这意味着我登录 Google 的用户有 2 "accounts"。一个帐户与 B运行d 帐户关联,另一个与我的 Google 用户关联。
我通过删除访问和刷新令牌重置了 Oath2 进程。这促使我再次允许应用程序访问请求的范围。首先,我看到一个典型的 YouTube 登录屏幕。然后,我看到一个屏幕,要求我在两个帐户之间 select;支持@leapfrogbic.om 或 LeapFrogBI。 b运行d 帐户是名为 LeapFrogBI 的帐户。
API 需要知道向应用程序发送哪个帐户 link 是有道理的。虽然这很令人困惑。 None 目前为止我找到的任何文档中都有。 F运行kly,我发现这个的唯一原因是因为我开始质疑我是否需要为 OnBehalfOfContentOwner 传递值。虽然我对命名法还不是 100% 清楚,但我想我明白是怎么回事了。
有了这些信息,我回去 运行 进行了一些测试。虽然 Oath2 被设置为使用 LeapFrogBI 帐户,但我没有收到任何工作!那是个大线索。因此,我将 Oath2 切换到 support@leapfrogbi.com 帐户,并获得了预期的工作列表。当然,所有视频都在 LeapFrogBI 帐户上,所以这可以解释为什么我在下载的报告中没有得到任何数据。
我在 LeapFrogBI 帐户上创建了报告,但报告需要 2 天才能可用。手指交叉。我希望这个问题得到解决,但我一定会让你知道无论哪种方式都会发生什么。
确认。我现在正在下载的 csv 中获取数据。