yt 0.13.9 → 0.13.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +4 -0
- data/lib/yt/collections/resumable_sessions.rb +8 -22
- data/lib/yt/models/account.rb +38 -3
- data/lib/yt/models/resumable_session.rb +10 -7
- data/lib/yt/models/video.rb +37 -0
- data/lib/yt/version.rb +1 -1
- data/spec/requests/as_account/authentications_spec.rb +1 -7
- data/spec/requests/as_account/thumbnail.jpg +0 -0
- data/spec/requests/as_account/video_spec.rb +22 -0
- metadata +4 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: f38c80c9cc34b749849ed9934a037fe7707614ce
         | 
| 4 | 
            +
              data.tar.gz: 2a9a06c9f14a9fabe19aa0d74e47e2a2fe2aaf6f
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: d39da84ceb5bd9941ea7a90b32ca01e2c94d1aa101289ac7ff012728663f08279bf2d6e961761aeb3043f973fe9304109d4449b95c45e78126784bc7d278bdc4
         | 
| 7 | 
            +
              data.tar.gz: fed816b3f0ef773b7b3f1050135c1a1e08b953ada0ba4aeafc69571c9e0f0408158190a20bcb4be0f4bca803a246254d2738502fed05ec4b4c61f512e09c585c
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -6,6 +6,10 @@ For more information about changelogs, check | |
| 6 6 | 
             
            [Keep a Changelog](http://keepachangelog.com) and
         | 
| 7 7 | 
             
            [Vandamme](http://tech-angels.github.io/vandamme).
         | 
| 8 8 |  | 
| 9 | 
            +
            ## 0.13.9 - 2015-02-17
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            * [FEATURE] New `video.upload_thumbnail` to upload the thumbnail for a video.
         | 
| 12 | 
            +
             | 
| 9 13 | 
             
            ## 0.13.9 - 2015-02-16
         | 
| 10 14 |  | 
| 11 15 | 
             
            * [ENHANCEMENT] Accept `force: true` in `authentication_url` to force approval prompt.
         | 
    
        data/README.md
    CHANGED
    
    | @@ -236,6 +236,7 @@ Use [Yt::Video](http://rubydoc.info/github/Fullscreen/yt/master/Yt/Models/Video) | |
| 236 236 |  | 
| 237 237 | 
             
            * read the attributes of a video
         | 
| 238 238 | 
             
            * update the attributes of a video
         | 
| 239 | 
            +
            * upload a thumbnail for a video
         | 
| 239 240 | 
             
            * access the annotations of a video
         | 
| 240 241 | 
             
            * delete a video
         | 
| 241 242 | 
             
            * like and dislike a video
         | 
| @@ -322,6 +323,9 @@ video = Yt::Video.new id: 'MESycYJytkU', auth: account | |
| 322 323 | 
             
            video.update title: 'A title', description: 'A description <with angle brackets>'
         | 
| 323 324 | 
             
            video.update tags: ['a tag'], categoryId: '21', license: 'creativeCommon'
         | 
| 324 325 |  | 
| 326 | 
            +
            video.upload_thumbnail 'my_thumbnail.jpg'
         | 
| 327 | 
            +
            video.upload_thumbnail 'http://example.com/remote.png'
         | 
| 328 | 
            +
             | 
| 325 329 | 
             
            video.views since: 7.days.ago #=> {Wed, 28 May 2014 => 12.0, Thu, 29 May 2014 => 3.0, …}
         | 
| 326 330 | 
             
            video.comments until: 2.days.ago #=> {Wed, 28 May 2014 => 9.0, Thu, 29 May 2014 => 4.0, …}
         | 
| 327 331 | 
             
            video.likes from: 8.days.ago #=> {Tue, 27 May 2014 => 7.0, Wed, 28 May 2014 => 0.0, …}
         | 
| @@ -11,26 +11,12 @@ module Yt | |
| 11 11 | 
             
                class ResumableSessions < Base
         | 
| 12 12 |  | 
| 13 13 | 
             
                  # Starts a resumable session by sending to YouTube the metadata of the
         | 
| 14 | 
            -
                  #  | 
| 15 | 
            -
                  # URL to upload the  | 
| 16 | 
            -
                  # @param [Integer] content_length the size (bytes) of the  | 
| 17 | 
            -
                  # @param [Hash] options the metadata to add to the uploaded  | 
| 18 | 
            -
                   | 
| 19 | 
            -
                  # @option options [String] :description The video’s description.
         | 
| 20 | 
            -
                  # @option options [Array<String>] :title The video’s tags.
         | 
| 21 | 
            -
                  # @option options [Integer] :category_id The video’s category ID.
         | 
| 22 | 
            -
                  # @option options [String] :privacy_status The video’s privacy status.
         | 
| 23 | 
            -
                  def insert(content_length, options = {})
         | 
| 14 | 
            +
                  # object to upload. If the request succeeds, YouTube returns a unique
         | 
| 15 | 
            +
                  # URL to upload the object file (and eventually resume the upload).
         | 
| 16 | 
            +
                  # @param [Integer] content_length the size (bytes) of the object to upload.
         | 
| 17 | 
            +
                  # @param [Hash] options the metadata to add to the uploaded object.
         | 
| 18 | 
            +
                  def insert(content_length, body = {})
         | 
| 24 19 | 
             
                    @headers = headers_for content_length
         | 
| 25 | 
            -
                    body = {}
         | 
| 26 | 
            -
             | 
| 27 | 
            -
                    snippet = options.slice :title, :description, :tags, :category_id
         | 
| 28 | 
            -
                    snippet[:categoryId] = snippet.delete(:category_id) if snippet[:category_id]
         | 
| 29 | 
            -
                    body[:snippet] = snippet if snippet.any?
         | 
| 30 | 
            -
             | 
| 31 | 
            -
                    status = options[:privacy_status]
         | 
| 32 | 
            -
                    body[:status] = {privacyStatus: status} if status
         | 
| 33 | 
            -
             | 
| 34 20 | 
             
                    do_insert body: body, headers: @headers
         | 
| 35 21 | 
             
                  end
         | 
| 36 22 |  | 
| @@ -43,15 +29,15 @@ module Yt | |
| 43 29 | 
             
                  def insert_params
         | 
| 44 30 | 
             
                    super.tap do |params|
         | 
| 45 31 | 
             
                      params[:response_format] = nil
         | 
| 46 | 
            -
                      params[:path] =  | 
| 47 | 
            -
                      params[:params] =  | 
| 32 | 
            +
                      params[:path] = @parent.upload_path
         | 
| 33 | 
            +
                      params[:params] = @parent.upload_params.merge uploadType: 'resumable'
         | 
| 48 34 | 
             
                    end
         | 
| 49 35 | 
             
                  end
         | 
| 50 36 |  | 
| 51 37 | 
             
                  def headers_for(content_length)
         | 
| 52 38 | 
             
                    {}.tap do |headers|
         | 
| 53 39 | 
             
                      headers['x-upload-content-length'] = content_length
         | 
| 54 | 
            -
                      headers['X-Upload-Content-Type'] =  | 
| 40 | 
            +
                      headers['X-Upload-Content-Type'] = @parent.upload_content_type
         | 
| 55 41 | 
             
                    end
         | 
| 56 42 | 
             
                  end
         | 
| 57 43 |  | 
    
        data/lib/yt/models/account.rb
    CHANGED
    
    | @@ -46,7 +46,7 @@ module Yt | |
| 46 46 | 
             
                  #   @return [Yt::Collections::Playlists] the account’s playlists.
         | 
| 47 47 | 
             
                  has_many :playlists
         | 
| 48 48 |  | 
| 49 | 
            -
                  # Uploads a video
         | 
| 49 | 
            +
                  # Uploads a video using resumable sessions
         | 
| 50 50 | 
             
                  # @param [String] path_or_url the video to upload. Can either be the
         | 
| 51 51 | 
             
                  #   path of a local file or the URL of a remote file.
         | 
| 52 52 | 
             
                  # @param [Hash] params the metadata to add to the uploaded video.
         | 
| @@ -57,8 +57,11 @@ module Yt | |
| 57 57 | 
             
                  # @return [Yt::Models::Video] the newly uploaded video.
         | 
| 58 58 | 
             
                  def upload_video(path_or_url, params = {})
         | 
| 59 59 | 
             
                    file = open path_or_url, 'rb'
         | 
| 60 | 
            -
                    session = resumable_sessions.insert file.size, params
         | 
| 61 | 
            -
             | 
| 60 | 
            +
                    session = resumable_sessions.insert file.size, upload_body(params)
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                    session.update(body: file) do |data|
         | 
| 63 | 
            +
                      Yt::Video.new id: data['id'], snippet: data['snippet'], status: data['privacyStatus'], auth: self
         | 
| 64 | 
            +
                    end
         | 
| 62 65 | 
             
                  end
         | 
| 63 66 |  | 
| 64 67 | 
             
                  def create_playlist(params = {})
         | 
| @@ -71,6 +74,38 @@ module Yt | |
| 71 74 | 
             
                  def videos_params
         | 
| 72 75 | 
             
                    {for_mine: true}
         | 
| 73 76 | 
             
                  end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  # @private
         | 
| 79 | 
            +
                  # Tells `has_many :resumable_sessions` what path to hit to upload a file.
         | 
| 80 | 
            +
                  def upload_path
         | 
| 81 | 
            +
                    '/upload/youtube/v3/videos'
         | 
| 82 | 
            +
                  end
         | 
| 83 | 
            +
                  # @private
         | 
| 84 | 
            +
                  # Tells `has_many :resumable_sessions` what params are set for the object
         | 
| 85 | 
            +
                  # associated to the uploaded file.
         | 
| 86 | 
            +
                  def upload_params
         | 
| 87 | 
            +
                    {part: 'snippet,status'}
         | 
| 88 | 
            +
                  end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                  # @private
         | 
| 91 | 
            +
                  # Tells `has_many :resumable_sessions` what metadata to set in the object
         | 
| 92 | 
            +
                  # associated to the uploaded file.
         | 
| 93 | 
            +
                  def upload_body(params = {})
         | 
| 94 | 
            +
                    {}.tap do |body|
         | 
| 95 | 
            +
                      snippet = params.slice :title, :description, :tags, :category_id
         | 
| 96 | 
            +
                      snippet[:categoryId] = snippet.delete(:category_id) if snippet[:category_id]
         | 
| 97 | 
            +
                      body[:snippet] = snippet if snippet.any?
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                      status = params[:privacy_status]
         | 
| 100 | 
            +
                      body[:status] = {privacyStatus: status} if status
         | 
| 101 | 
            +
                    end
         | 
| 102 | 
            +
                  end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                  # @private
         | 
| 105 | 
            +
                  # Tells `has_many :resumable_sessions` what type of file can be uploaded.
         | 
| 106 | 
            +
                  def upload_content_type
         | 
| 107 | 
            +
                    'video/*'
         | 
| 108 | 
            +
                  end
         | 
| 74 109 | 
             
                end
         | 
| 75 110 | 
             
              end
         | 
| 76 111 | 
             
            end
         | 
| @@ -13,14 +13,17 @@ module Yt | |
| 13 13 | 
             
                    @headers = options[:headers]
         | 
| 14 14 | 
             
                  end
         | 
| 15 15 |  | 
| 16 | 
            -
                   | 
| 17 | 
            -
             | 
| 16 | 
            +
                  def update(params = {})
         | 
| 17 | 
            +
                    do_update(params) {|data| yield data}
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  # Uploads a thumbnail using the current resumable session
         | 
| 21 | 
            +
                  # @param [#read] file A binary object that contains the image content.
         | 
| 18 22 | 
             
                  #   Can either be a File, a StringIO (for instance using open-uri), etc.
         | 
| 19 | 
            -
                  # @return  | 
| 20 | 
            -
                   | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
                    end
         | 
| 23 | 
            +
                  # @return the new thumbnail resource for the given image.
         | 
| 24 | 
            +
                  # @see https://developers.google.com/youtube/v3/docs/thumbnails#resource
         | 
| 25 | 
            +
                  def upload_thumbnail(file)
         | 
| 26 | 
            +
                    do_update(body: file) {|data| data['items'].first}
         | 
| 24 27 | 
             
                  end
         | 
| 25 28 |  | 
| 26 29 | 
             
                private
         | 
    
        data/lib/yt/models/video.rb
    CHANGED
    
    | @@ -73,6 +73,11 @@ module Yt | |
| 73 73 | 
             
                  delegate :view_count, :like_count, :dislike_count, :favorite_count,
         | 
| 74 74 | 
             
                    :comment_count, to: :statistics_set
         | 
| 75 75 |  | 
| 76 | 
            +
                  # @!attribute [r] resumable_sessions
         | 
| 77 | 
            +
                  #   @return [Yt::Collections::ResumableSessions] the sessions used to
         | 
| 78 | 
            +
                  #     upload thumbnails using the resumable upload protocol.
         | 
| 79 | 
            +
                  has_many :resumable_sessions
         | 
| 80 | 
            +
             | 
| 76 81 | 
             
                  # Override Resource's new to set statistics and content details as well
         | 
| 77 82 | 
             
                  # if the response includes them
         | 
| 78 83 | 
             
                  def initialize(options = {})
         | 
| @@ -163,6 +168,20 @@ module Yt | |
| 163 168 | 
             
                    !liked?
         | 
| 164 169 | 
             
                  end
         | 
| 165 170 |  | 
| 171 | 
            +
                  # Uploads a thumbnail
         | 
| 172 | 
            +
                  # @param [String] path_or_url the image to upload. Can either be the
         | 
| 173 | 
            +
                  #   path of a local file or the URL of a remote file.
         | 
| 174 | 
            +
                  # @return the new thumbnail resource for the given image.
         | 
| 175 | 
            +
                  # @see https://developers.google.com/youtube/v3/docs/thumbnails#resource
         | 
| 176 | 
            +
                  def upload_thumbnail(path_or_url)
         | 
| 177 | 
            +
                    file = open path_or_url, 'rb'
         | 
| 178 | 
            +
                    session = resumable_sessions.insert file.size
         | 
| 179 | 
            +
             | 
| 180 | 
            +
                    session.update(body: file) do |data|
         | 
| 181 | 
            +
                      snippet.instance_variable_set :@thumbnails, data['items'].first
         | 
| 182 | 
            +
                    end
         | 
| 183 | 
            +
                  end
         | 
| 184 | 
            +
             | 
| 166 185 | 
             
                  # @private
         | 
| 167 186 | 
             
                  # Tells `has_reports` to retrieve the reports from YouTube Analytics API
         | 
| 168 187 | 
             
                  # either as a Channel or as a Content Owner.
         | 
| @@ -178,6 +197,24 @@ module Yt | |
| 178 197 | 
             
                    end
         | 
| 179 198 | 
             
                  end
         | 
| 180 199 |  | 
| 200 | 
            +
                  # @private
         | 
| 201 | 
            +
                  # Tells `has_many :resumable_sessions` what path to hit to upload a file.
         | 
| 202 | 
            +
                  def upload_path
         | 
| 203 | 
            +
                    '/upload/youtube/v3/thumbnails/set'
         | 
| 204 | 
            +
                  end
         | 
| 205 | 
            +
                  # @private
         | 
| 206 | 
            +
                  # Tells `has_many :resumable_sessions` what params are set for the object
         | 
| 207 | 
            +
                  # associated to the uploaded file.
         | 
| 208 | 
            +
                  def upload_params
         | 
| 209 | 
            +
                    {video_id: id}
         | 
| 210 | 
            +
                  end
         | 
| 211 | 
            +
             | 
| 212 | 
            +
                  # @private
         | 
| 213 | 
            +
                  # Tells `has_many :resumable_sessions` what type of file can be uploaded.
         | 
| 214 | 
            +
                  def upload_content_type
         | 
| 215 | 
            +
                    'application/octet-stream'
         | 
| 216 | 
            +
                  end
         | 
| 217 | 
            +
             | 
| 181 218 | 
             
                private
         | 
| 182 219 |  | 
| 183 220 | 
             
                  # @see https://developers.google.com/youtube/v3/docs/videos/update
         | 
    
        data/lib/yt/version.rb
    CHANGED
    
    
| @@ -109,15 +109,9 @@ describe Yt::Account, :device_app do | |
| 109 109 | 
             
                    it { expect{account.authentication}.to raise_error Yt::Errors::MissingAuth }
         | 
| 110 110 | 
             
                  end
         | 
| 111 111 |  | 
| 112 | 
            -
                  # @note: This test is a reflection of another irrational behavior of
         | 
| 113 | 
            -
                  #   YouTube API. When passing a wrong 'device_code', YouTube crashes and
         | 
| 114 | 
            -
                  #   raises 500, instead of an expected MissingAuth.
         | 
| 115 | 
            -
                  #   The day YouTube fixes it, then this test will finally fail and the
         | 
| 116 | 
            -
                  #   commented line will be restored.
         | 
| 117 112 | 
             
                  context 'and an invalid device code' do
         | 
| 118 113 | 
             
                    before { attrs[:device_code] = '--not-a-valid-device-code--' }
         | 
| 119 | 
            -
                     | 
| 120 | 
            -
                    it { expect{account.authentication}.to raise_error Yt::Errors::ServerError }
         | 
| 114 | 
            +
                    it { expect{account.authentication}.to raise_error Yt::Errors::MissingAuth }
         | 
| 121 115 | 
             
                  end
         | 
| 122 116 | 
             
                end
         | 
| 123 117 |  | 
| Binary file | 
| @@ -342,4 +342,26 @@ describe Yt::Video, :device_app do | |
| 342 342 | 
             
                  end
         | 
| 343 343 | 
             
                end
         | 
| 344 344 | 
             
              end
         | 
| 345 | 
            +
             | 
| 346 | 
            +
              # @note: This should somehow test that the thumbnail *changes*. However,
         | 
| 347 | 
            +
              #   YouTube does not change the URL of the thumbnail even though the content
         | 
| 348 | 
            +
              #   changes. A full test would have to *download* the thumbnails before and
         | 
| 349 | 
            +
              #   after, and compare the files. For now, not raising error is enough.
         | 
| 350 | 
            +
              #   Eventually, change to `expect{update}.to change{video.thumbnail_url}`
         | 
| 351 | 
            +
              context 'given one of my own videos for which I want to upload a thumbnail' do
         | 
| 352 | 
            +
                let(:id) { $account.videos.where(order: 'viewCount').first.id }
         | 
| 353 | 
            +
                let(:update) { video.upload_thumbnail path_or_url }
         | 
| 354 | 
            +
             | 
| 355 | 
            +
                context 'given the path to a local JPG image file' do
         | 
| 356 | 
            +
                  let(:path_or_url) { File.expand_path '../thumbnail.jpg', __FILE__ }
         | 
| 357 | 
            +
             | 
| 358 | 
            +
                  it { expect{update}.not_to raise_error }
         | 
| 359 | 
            +
                end
         | 
| 360 | 
            +
             | 
| 361 | 
            +
                context 'given the path to a remote PNG image file' do
         | 
| 362 | 
            +
                  let(:path_or_url) { 'https://bit.ly/yt_thumbnail' }
         | 
| 363 | 
            +
             | 
| 364 | 
            +
                  it { expect{update}.not_to raise_error }
         | 
| 365 | 
            +
                end
         | 
| 366 | 
            +
              end
         | 
| 345 367 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: yt
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.13. | 
| 4 | 
            +
              version: 0.13.10
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Claudio Baccigalupo
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2015-02- | 
| 11 | 
            +
            date: 2015-02-17 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: activesupport
         | 
| @@ -257,6 +257,7 @@ files: | |
| 257 257 | 
             
            - spec/requests/as_account/playlist_item_spec.rb
         | 
| 258 258 | 
             
            - spec/requests/as_account/playlist_spec.rb
         | 
| 259 259 | 
             
            - spec/requests/as_account/resource_spec.rb
         | 
| 260 | 
            +
            - spec/requests/as_account/thumbnail.jpg
         | 
| 260 261 | 
             
            - spec/requests/as_account/video.mp4
         | 
| 261 262 | 
             
            - spec/requests/as_account/video_spec.rb
         | 
| 262 263 | 
             
            - spec/requests/as_content_owner/account_spec.rb
         | 
| @@ -353,6 +354,7 @@ test_files: | |
| 353 354 | 
             
            - spec/requests/as_account/playlist_item_spec.rb
         | 
| 354 355 | 
             
            - spec/requests/as_account/playlist_spec.rb
         | 
| 355 356 | 
             
            - spec/requests/as_account/resource_spec.rb
         | 
| 357 | 
            +
            - spec/requests/as_account/thumbnail.jpg
         | 
| 356 358 | 
             
            - spec/requests/as_account/video.mp4
         | 
| 357 359 | 
             
            - spec/requests/as_account/video_spec.rb
         | 
| 358 360 | 
             
            - spec/requests/as_content_owner/account_spec.rb
         |