如何使用media.download下载YouTube报告 [英] How to download YouTube report using media.download

查看:100
本文介绍了如何使用media.download下载YouTube报告的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一个示例,该示例说明了如何使用YouTube报告API的.Net客户端库下载报告.我已经过身份验证,创建了作业,并检索了包括reportUrl值的报告列表.我无法弄清楚如何使用media.download方法实际下载报告并将其保存在本地.

I'm looking for an example which explains how to download reports using the .Net client library for YouTube Reporting API. I have authenticated, created jobs, and retrieved a list of reports including reportUrl values. I'm unable to figure out how to use the media.download method to actually download the report and save it locally.

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

Update 20170405

我相信我看到的问题与提供下载URL的方式有关.经过大量的尝试和回顾之后,我找到了很少的文档,但最终得到了下面的代码,看起来似乎有所改进,但这仍然只返回标头.

I believe the problem I'm seeing has something to do with the way the download URL is being provided. After a lot of head scratching and reviewing what little documentation I could find, I ended up with the below code which seems like an improvement, but this still only 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,而不是解析它并将其用作资源名.可悲的是我得到了相同的结果.仅标头.没有数据.

20170406 Update I found some examples of code in other languages which led me to making the following changes. At least the download URL is being passed in directly instead of me parsing it and using it as the resourcename. Sadly I'm getting the same results; headers only. No data.

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

推荐答案

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

The final version of media.download in the post examples is correct.

我在YouTube中有一个品牌帐户".这意味着我登录Google的用户有2个帐户".一个帐户与品牌帐户相关联,一个帐户与我的Google用户相关联.

I have a "Brand Account" in YouTube. This means that the user I sign into Google with has 2 "accounts". One account is associated with the Brand Account, and one is associated with my Google user.

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

I reset the Oath2 process by deleting the access & refresh token. This prompted me to again allow the app access to the requested scopes. First, I'm presented with a typical YouTube login screen. Then, I'm presented with a screen that ask me to select between two accounts; support@leapfrogbic.om or LeapFrogBI. The brand account is the one named LeapFrogBI.

有意义的是,API需要知道链接到应用程序的帐户.但是,这很令人困惑.到目前为止,我没有找到任何文档.坦白说,我发现这的唯一原因是因为我开始质疑是否需要传递OnBehalfOfContentOwner的值.尽管我仍不清楚其术语的100%,但我想我了解发生了什么事.

It makes sense that the API would need to know which account to link to the application. It is quite confusing though. None of this is in any of the documentation I've found thus far. Frankly, the only reason I found this is because I started questioning whether I needed to pass in value for OnBehalfOfContentOwner. Although I'm still not 100% clear on the nomenclature, I think I understand what is going on.

有了这些信息,我回去进行了一些测试.当Oath2设置为使用LeapFrogBI帐户时,我没有收到任何工作!那是个大提示.因此,我将Oath2切换到了support@leapfrogbi.com帐户,并得到了我期望的工作清单.当然,所有视频都在LeapFrogBI帐户上,所以这可以解释为什么我在下载的报告中没有数据.

With this information I went back and ran a couple tests. While Oath2 was set to use the LeapFrogBI account, I received no jobs! That was the big clue. So, I switched Oath2 to the support@leapfrogbi.com account and I got my expected job list. Of course, all of the videos are on the LeapFrogBI account so this would explain why I'm getting no data in the downloaded reports.

我在LeapFrogBI帐户上创建了报告,但是需要2天的时间才能获得报告.手指交叉.我希望这个问题能够解决,但我一定会让您知道这两种情况会发生什么.

I created reports on the LeapFrogBI account, but it will take 2 days before the reports will be available. Fingers crossed. I'm hoping this problem is solved, but I'll definitely let you know what happens either way.

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

Confirmed. I'm getting data in the downloaded csv now.

这篇关于如何使用media.download下载YouTube报告的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆