如何使用media.download下载YouTube报告

时间:2017-04-03 19:10:23

标签: google-api-dotnet-client youtube-analytics-api

我正在寻找一个示例,说明如何使用YouTube报告API的.Net客户端库下载报告。我已经过身份验证,创建了作业,并检索了包含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

我相信我看到的问题与下载网址的提供方式有关。经过大量的讨论和审查我能找到的小文档后,我最终得到了下面的代码,这似乎是一种改进,但这仍然只返回标题。

                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是直接传入的,而不是我解析它并将其用作资源名称。可悲的是,我得到了同样的结果;仅限标题。没有数据。

                //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);
                }

1 个答案:

答案 0 :(得分:1)

帖子示例中的media.download的最终版本是正确的。

我有一个&#34;品牌帐户&#34;在YouTube中。这意味着我登录Google的用户拥有2&#34;帐户&#34;。一个帐户与品牌帐户相关联,一个帐户与我的Google用户相关联。

我通过删除访问权限来重置Oath2进程。刷新令牌。这促使我再次允许应用访问所请求的范围。首先,我提供了一个典型的YouTube登录屏幕。然后,我出现了一个屏幕,要求我在两个帐户之间进行选择; support@leapfrogbic.om或LeapFrogBI。品牌帐户名为LeapFrogBI。

API有必要知道链接到应用程序的帐户。但这很令人困惑。这些都不是我迄今为止发现的任何文档。坦率地说,我发现这个的唯一原因是因为我开始质疑我是否需要传递OnBehalfOfContentOwner的值。虽然我仍然没有100%明确命名,但我想我明白发生了什么。

有了这些信息,我回去做了几次测试。虽然Oath2设置使用LeapFrogBI帐户,但我没有找到工作!这是一个很大的线索。所以,我把Oath2改成了support@leapfrogbi.com帐户,我得到了我预期的工作清单。当然,所有视频都在LeapFrogBI帐户中,因此这可以解释为什么我在下载的报告中没有数据。

我创建了有关LeapFrogBI帐户的报告,但报告将需要2天才能提供。手指交叉。我希望这个问题能够得到解决,但我绝对会让你知道会发生什么。

确认。我现在正在下载的csv中获取数据。

相关问题