【问题标题】:How to insert video youtube api v3 through service account with ruby如何使用 ruby​​ 通过服务帐户插入视频 youtube api v3
【发布时间】:2015-02-20 22:23:32
【问题描述】:

我的目标是让我的应用用户通过我的服务器上传到我的 youtube 帐户。 我有一个开发者帐户,启用了 youtube 数据 api 和一个服务帐户客户端设置,但由于某种原因我没有被授权。我翻遍了网络试图找出原因并找到了很多东西。 我尝试使用项目客户端 ID 和范围在管理安全设置中授予权限。 很多人说这个错误是因为我没有与我的帐户关联的 youtube 帐户。但我不知道如何关联这些。

这是我的 upload_video.rb 脚本:

require 'rubygems'
require 'google/api_client'
require 'google/api_client/client_secrets'
require 'google/api_client/auth/file_storage'
require 'google/api_client/auth/installed_app'
require 'certified'

DEVELOPER_KEY = "MY-DEVELOPER-KEY"
YOUTUBE_UPLOAD_SCOPE = 'https://www.googleapis.com/auth/youtube.upload'
YOUTUBE_API_SERVICE_NAME = 'youtube'
YOUTUBE_API_VERSION = 'v3'

def get_authenticated_service
  puts @PROGRAM_NAME
  client = Google::APIClient.new(
    :application_name => $PROGRAM_NAME,
    :application_version => '1.0.0'
)

key = Google::APIClient::KeyUtils.load_from_pkcs12('oauth2service.p12', 'notasecret')
  auth_client = Signet::OAuth2::Client.new(
  :token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
  :audience => 'https://accounts.google.com/o/oauth2/token',
  :scope => YOUTUBE_UPLOAD_SCOPE,
  :issuer => 'SERVICE ACCOUNT EMAIL ADDRESS',
  :signing_key => key)
 auth_client.fetch_access_token!
 client.authorization = auth_client
 youtube = client.discovered_api(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION)
 return client, youtube
end

def upload2youtube file, title, description, category_id, keywords, privacy_status

  client, youtube = get_authenticated_service
  begin
    body = {
  :snippet => {
    :title => title,
    :description => description,
    :tags => keywords.split(','),
    :categoryId => category_id,
  },
  :status => {
    :privacyStatus => privacy_status
  }
}

videos_insert_response = client.execute!(
  :api_method => youtube.videos.insert,
  :body_object => body,
  :media => Google::APIClient::UploadIO.new(file, 'video/*'),
  :parameters => {
    :uploadType => 'resumable',
    :part => body.keys.join(',')
  }
 )

 videos_insert_response.resumable_upload.send_all(client)

 puts "Video id '#{videos_insert_response.data.id}' was successfully uploaded."
 rescue Google::APIClient::TransmissionError => e
 puts e.result.body
 end
end

这是我从另一个脚本运行它的方式:

require 'google/api_client'
require_relative 'upload_video'

$PROGRAM_NAME = 'MY-PROJECT-NAME'
upload2youtube File.open("somevideo.avi"), "title", "description", 'categoryid', 'tag1,tag2,tag3', 'unlisted'

结果如下:

{
 "error": {
  "errors": [
   {
    "domain": "youtube.header",
    "reason": "youtubeSignupRequired",
    "message": "Unauthorized",
    "locationType": "header",
    "location": "Authorization"
   }
  ],
  "code": 401,
  "message": "Unauthorized"
 }
}

我做错了什么

【问题讨论】:

    标签: ruby youtube youtube-api youtube-data-api


    【解决方案1】:
    #!/usr/bin/ruby
    
    require 'rubygems'
    require 'google/api_client'
    require 'google/api_client/client_secrets'
    require 'google/api_client/auth/file_storage'
    require 'google/api_client/auth/installed_app'
    require 'certified'
    
    
    class Youtube_Helper
    
      @@client_email = '' #email id from service account (that really long email address...)
      @@youtube_email = '' #email associated with youtube account
      @@p12_file_path = '' #path to the file downloaded from the service account (Generate new p12 key button)
      @@p12_password = '' # password to the file usually 'notasecret'
      @@api_key = nil # The API key for non authenticated things like lists
      YOUTUBE_UPLOAD_SCOPE = 'https://www.googleapis.com/auth/youtube.upload'
      YOUTUBE_API_SERVICE_NAME = 'youtube'
      YOUTUBE_API_VERSION = 'v3'
      @@client = nil
      @@youtube = nil
      FILE_POSTFIX = '-oauth2.json'
    
      def initialize(client_email, youtube_email, p12_file_path, p12_password, api_key)
        @@client_email=client_email
        @@youtube_email=youtube_email
        @@p12_file_path=p12_file_path
        @@p12_password=p12_password
        @@api_key = api_key
      end
    
      def get_authenticated_service
    
    
        credentialsFile = $0 + FILE_POSTFIX
    
        needtoauthenticate = false
    
        @api_client = Google::APIClient.new(
          :application_name => $PROGRAM_NAME,
          :application_version => '1.0.0'
        )
    
        key = Google::APIClient::KeyUtils.load_from_pkcs12(@@p12_file_path, @@p12_password)
        @auth_client = Signet::OAuth2::Client.new(
            :token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
            :audience => 'https://accounts.google.com/o/oauth2/token',
            :scope => YOUTUBE_UPLOAD_SCOPE,
            :issuer => @@client_email,
            :person => @@youtube_email,
            :signing_key => key)
    
    
        if File.exist? credentialsFile
          puts 'credential file exists'
          puts credentialsFile.to_s
          File.open(credentialsFile, 'r') do |file|
            credentials = JSON.load(file)
            if !credentials.nil?
              puts 'get credentials from file'
              @auth_client.access_token = credentials['access_token']
              @auth_client.client_id = credentials['client_id']
              @auth_client.client_secret = credentials['client_secret']
              @auth_client.refresh_token = credentials['refresh_token']
              @auth_client.expires_in = (Time.parse(credentials['token_expiry']) - Time.now).ceil
              @api_client.authorization = @auth_client
              if @auth_client.expired?
                puts 'authorization expired'
                needtoauthenticate = true
              end
            else
              needtoauthenticate = true
            end
          end
        else
          needtoauthenticate = true
        end
    
        if needtoauthenticate
          @auth_client.fetch_access_token!
          @api_client.authorization = @auth_client
          save(credentialsFile)
        end
    
        youtube = @api_client.discovered_api(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION)
        @@client = @api_client
        @@youtube = youtube
        return @api_client, youtube
      end
    
      def save(credentialsFile)
        File.open(credentialsFile, 'w', 0600) do |file|
          json = JSON.dump({
            :access_token => @auth_client.access_token,
            :client_id => @auth_client.client_id,
            :client_secret => @auth_client.client_secret,
            :refresh_token => @auth_client.refresh_token,
            :token_expiry => @auth_client.expires_at
          })
          file.write(json)
        end
      end
    
      def upload2youtube file, title, description, category_id, keywords, privacy_status
        puts 'begin'
        begin
          body = {
            :snippet => {
              :title => title,
              :description => description,
              :tags => keywords.split(','),
              :categoryId => category_id,
            },
            :status => {
              :privacyStatus => privacy_status
            }
          }
          puts body.keys.join(',')
    
          # Call the API's videos.insert method to create and upload the video.
          videos_insert_response = @@client.execute!(
            :api_method => @@youtube.videos.insert,
            :body_object => body,
            :media => Google::APIClient::UploadIO.new(file, 'video/*'),
            :parameters => {
              'uploadType' => 'multipart',
              :part => body.keys.join(',')
            }
          )
    
          puts'inserted'
    
          puts "'#{videos_insert_response.data.snippet.title}' (video id: #{videos_insert_response.data.id}) was successfully uploaded."
    
        rescue Google::APIClient::TransmissionError => e
          puts e.result.body
        end
    
        return videos_insert_response.data.id #video id
    
      end
    
      def upload_thumbnail  video_id, thumbnail_file, thumbnail_size
        puts 'uploading thumbnail'
        begin
          thumbnail_upload_response = @@client.execute({ :api_method => @@youtube.thumbnails.set,
                                :parameters => { :videoId => video_id,
                                                 'uploadType' => 'media',
                                                 :onBehalfOfContentOwner => @@youtube_email},
                                :media => thumbnail_file,
                                :headers => { 'Content-Length' => thumbnail_size.to_s,
                                              'Content-Type' => 'image/jpg' }
                                })
        rescue Google::APIClient::TransmissionError => e
            puts e.result.body 
        end 
      end
    
      def get_video_statistics video_id
        client = Google::APIClient.new(:key => @@api_key,
                                        :application_name => $PROGRAM_NAME,
                                        :application_version => '1.0.0',
                                        :authorization => nil)
        youtube = client.discovered_api(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION)
        stats_response = client.execute!( :api_method => youtube.videos.list,
                        :parameters => {:part => 'statistics', :id => video_id }
                        )
        return stats_response
      end
    end
    

    【讨论】:

    • 我收到 Signet::AuthorizationError:授权失败。服务器消息:{ "error" : "invalid_grant" }
    • @venkatareddy 你现在试过代码了吗?我编辑了它。请告诉我它是否有效
    • 对不起,伙计。我对使用服务帐户不再感兴趣,因为 youtube API v3 已弃用服务帐户。感谢您的时间和帮助!
    • 我们如何在 PHP 中实现相同的功能。
    猜你喜欢
    • 2019-01-11
    • 2016-06-05
    • 2016-06-25
    • 1970-01-01
    • 2017-03-29
    • 2014-02-17
    • 2013-12-16
    • 2013-10-11
    • 2014-01-06
    相关资源
    最近更新 更多