yt 0.6.4 → 0.6.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ec366e6612cd8a61ec3067f58c819426b4da21ad
4
- data.tar.gz: 3708e2efffd1b660afe370630d2f9b86e23f9e59
3
+ metadata.gz: 8c7f28e1adc91466df73429cd2e12988092acabd
4
+ data.tar.gz: a66cb8c64a3764ffcad1e1988fa025ca5a9d5094
5
5
  SHA512:
6
- metadata.gz: 33b816e4a002b24218b08b602c1faf999c854e04fa2edd3a3c84127ee0860463fe68ef8a07577d18830443497347ce55f968320503e5f27706b9e558be3cd884
7
- data.tar.gz: 7e802cf425854455fd936424312f1343ce82a7bd35032b373cfb17df6b2c811525668013e91e2d7b7c3999725cf93d211e042981ff8dbbe55d58e7a3fa0eace5
6
+ metadata.gz: b422e2ac62121f98113de5a65f53c2925009ddc3dc78737ffa9c145427201eb53df3723ebe0cdde108f5dfcfa05655c3bea9413ec03309e363075214a01b760a
7
+ data.tar.gz: 90bcf64d69cbb1161f694d22b5782cedcc0668f34025824fdea4da2e396af80a28b263abf9f52b0508cf14f7fe14c8f75ae49788cdc520e6b0395d9e5f4ada08
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- yt (0.6.4)
4
+ yt (0.6.5)
5
5
  activesupport
6
6
 
7
7
  GEM
data/HISTORY.md CHANGED
@@ -7,6 +7,7 @@ v0.6 - 2014/06/05
7
7
  * Allow account.videos to be chained with .where, such as in account.videos.where(q: 'query')
8
8
  * Retry request once when YouTube times out
9
9
  * Handle annotations with "never" as the timestamp, without text, singleton positions, of private videos
10
+ * New methods for Video: hd?, stereoscopic?, captioned?, licensed?
10
11
 
11
12
  v0.5 - 2014/05/16
12
13
  -----------------
data/README.md CHANGED
@@ -27,6 +27,10 @@ video = Yt::Video.new id: 'MESycYJytkU'
27
27
  video.title #=> "Fullscreen Creator Platform"
28
28
  video.public? #=> true
29
29
  video.duration #=> 86
30
+ video.hd? #=> true
31
+ video.stereoscopic? #=> false
32
+ video.captioned? #=> true
33
+ video.licensed? #=> false
30
34
  video.annotations.count #=> 1
31
35
  ```
32
36
 
@@ -332,7 +336,7 @@ To install on your system, run
332
336
 
333
337
  To use inside a bundled Ruby project, add this line to the Gemfile:
334
338
 
335
- gem 'yt', '~> 0.6.4'
339
+ gem 'yt', '~> 0.6.5'
336
340
 
337
341
  Since the gem follows [Semantic Versioning](http://semver.org),
338
342
  indicating the full version in your Gemfile (~> *major*.*minor*.*patch*)
data/TODO.md CHANGED
@@ -1,13 +1,58 @@
1
1
  * methods like Yt::Account.new(params = {}) should use HashWithIndifferentAccess
2
2
  * add canonical_url to Resource, then use it in promo
3
3
 
4
- * once in a while, Google fails with 500 error and just retrying after some
5
- seconds fixes it, so we should retry every 500 at least
4
+ List of supported methods
5
+ =========================
6
6
 
7
- * find by url (either video or channel or.. playlist)
8
- * Google accounts?
9
- * ENV support
7
+ YouTube Data API V3 (https://developers.google.com/youtube/v3/docs)
8
+ -------------------------------------------------------------------
10
9
 
11
- * operations like subscribe that require authentication should not fail if
12
- called on Yt::Channel without auth but, similarly to account, show the prompt
13
- or ask for the device code
10
+ - [ ] Activities
11
+ - [ ] list
12
+ - [ ] insert
13
+ - [ ] ChannelBanners
14
+ - [ ] insert
15
+ - [ ] Channels
16
+ - [ ] list
17
+ - [ ] update
18
+ - [ ] ChannelSections
19
+ - [ ] list
20
+ - [ ] insert
21
+ - [ ] update
22
+ - [ ] delete
23
+ - [ ] GuideCategories
24
+ - [ ] list
25
+ - [ ] I18nLanguages
26
+ - [ ] list
27
+ - [ ] I18nRegions
28
+ - [ ] list
29
+ - [ ] PlaylistItems
30
+ - [ ] list
31
+ - [ ] insert
32
+ - [ ] update
33
+ - [ ] delete
34
+ - [ ] Playlists
35
+ - [ ] list
36
+ - [ ] insert
37
+ - [ ] update
38
+ - [ ] delete
39
+ - [ ] Search
40
+ - [ ] list
41
+ - [ ] Subscriptions
42
+ - [ ] list
43
+ - [ ] insert
44
+ - [ ] delete
45
+ - [ ] Thumbnails
46
+ - [ ] set
47
+ - [ ] VideoCategories
48
+ - [ ] list
49
+ - [ ] Videos
50
+ - [ ] list
51
+ - [ ] insert
52
+ - [ ] update
53
+ - [ ] rate
54
+ - [ ] getRating
55
+ - [ ] delete
56
+ - [ ] Watermarks
57
+ - [ ] set
58
+ - [ ] unset
data/bin/yt CHANGED
@@ -23,4 +23,8 @@ channel.videos.each do |video|
23
23
  puts " Description: #{video.description}"
24
24
  puts " Thumbnail: #{video.thumbnail_url}"
25
25
  puts " Public? #{video.public?}"
26
+ puts " hd? #{video.hd?}"
27
+ puts " stereoscopic? #{video.stereoscopic?}"
28
+ puts " captioned? #{video.captioned?}"
29
+ puts " licensed? #{video.licensed?}"
26
30
  end
@@ -8,9 +8,9 @@ module Yt
8
8
 
9
9
  private
10
10
 
11
- def do_delete_all(params = {})
11
+ def do_delete_all(params = {}, options = {})
12
12
  list_all(params).map do |item|
13
- item.delete
13
+ item.delete options
14
14
  end.tap { @items = [] }
15
15
  end
16
16
 
@@ -8,7 +8,7 @@ module Yt
8
8
  alias size count
9
9
 
10
10
  def first!
11
- first.tap{|item| raise Errors::NoItems unless item}
11
+ first.tap{|item| raise Errors::NoItems, last_request unless item}
12
12
  end
13
13
 
14
14
  private
@@ -48,13 +48,20 @@ module Yt
48
48
  end
49
49
 
50
50
  def fetch_page(params = {})
51
- request = Yt::Request.new params
52
- response = request.run
51
+ response = request(params).run
53
52
  token = response.body['nextPageToken']
54
53
  items = response.body.fetch items_key, []
55
54
  {items: items, token: token}
56
55
  end
57
56
 
57
+ def request(params = {})
58
+ @last_request = Yt::Request.new params
59
+ end
60
+
61
+ def last_request
62
+ @last_request.request_error_message if @last_request
63
+ end
64
+
58
65
  def list_params
59
66
  path = "/youtube/v3/#{list_resources.to_s.demodulize.camelize :lower}"
60
67
 
@@ -40,9 +40,10 @@ module Yt
40
40
  data.last
41
41
  end
42
42
 
43
- def metrics
44
- ''
45
- end
43
+ # To be overriden by superclasses
44
+ # def metrics
45
+ # ''
46
+ # end
46
47
 
47
48
  def items_key
48
49
  'rows'
@@ -15,7 +15,7 @@ module Yt
15
15
 
16
16
  def delete_all(params = {}, options = {})
17
17
  throttle
18
- do_delete_all params
18
+ do_delete_all params, options
19
19
  end
20
20
 
21
21
  private
@@ -4,7 +4,7 @@ require 'yt/associations/views'
4
4
 
5
5
  module Yt
6
6
  module Models
7
- # Provides methods to interact with YouTube channels.
7
+ # A channel resource contains information about a YouTube channel.
8
8
  # @see https://developers.google.com/youtube/v3/docs/channels
9
9
  class Channel < Resource
10
10
  include Associations::Earnings
@@ -2,8 +2,8 @@ require 'yt/models/base'
2
2
 
3
3
  module Yt
4
4
  module Models
5
- # Encapsulates information about the content of a resource, for
6
- # instance a video.
5
+ # Encapsulates information about the video content, including the length
6
+ # of the video and an indication of whether captions are available.
7
7
  # @see https://developers.google.com/youtube/v3/docs/videos#resource
8
8
  class DetailsSet < Base
9
9
 
@@ -11,9 +11,30 @@ module Yt
11
11
  @data = options[:data]
12
12
  end
13
13
 
14
- # @return [Integer] the duration of the resource (in seconds).
14
+ # @return [Integer] the duration of the video (in seconds).
15
15
  def duration
16
- @duration = to_seconds @data.fetch('duration', 0)
16
+ @duration ||= to_seconds @data.fetch('duration', 0)
17
+ end
18
+
19
+ # @return [Boolean] whether the video is available in 3D.
20
+ def stereoscopic?
21
+ @stereoscopic ||= @data['dimension'] == '3d'
22
+ end
23
+
24
+ # @return [Boolean] whether the video is available in high definition.
25
+ def hd?
26
+ @hd ||= @data['definition'] == 'hd'
27
+ end
28
+
29
+ # @return [Boolean] whether captions are available for the video.
30
+ def captioned?
31
+ @hd ||= @data['caption'] == 'true'
32
+ end
33
+
34
+ # @return [Boolean] whether the video represents licensed content, which
35
+ # means that the content has been claimed by a YouTube content partner.
36
+ def licensed?
37
+ @licensed ||= @data.fetch 'licensedContent', false
17
38
  end
18
39
 
19
40
  private
@@ -17,7 +17,7 @@ module Yt
17
17
  # @raise [Yt::Errors::Unauthorized] if {Resource#auth auth} does not
18
18
  # return an account with permissions to delete the playlist.
19
19
  # @return [Boolean] whether the playlist does not exist anymore.
20
- def delete
20
+ def delete(options = {})
21
21
  do_delete {@id = nil}
22
22
  !exists?
23
23
  end
@@ -24,7 +24,7 @@ module Yt
24
24
  end
25
25
  end
26
26
 
27
- def delete
27
+ def delete(options = {})
28
28
  do_delete {@id = nil}
29
29
  !exists?
30
30
  end
@@ -19,7 +19,7 @@ module Yt
19
19
  @body_type = options.fetch :body_type, :json
20
20
  @expected_response = options.fetch :expected_response, Net::HTTPSuccess
21
21
  @format = options.fetch :format, :json
22
- @headers = options.fetch :headers, {}
22
+ @headers = options.fetch :headers, gzip_headers
23
23
  @host = options.fetch :host, google_api_host
24
24
  @method = options.fetch :method, :get
25
25
  @path = options[:path]
@@ -34,6 +34,13 @@ module Yt
34
34
  end
35
35
  end
36
36
 
37
+ def request_error_message
38
+ {}.tap do |message|
39
+ message[:request_curl] = as_curl
40
+ message[:response_body] = JSON(response.body) rescue response.inspect
41
+ end.to_json
42
+ end
43
+
37
44
  private
38
45
 
39
46
  def response
@@ -59,6 +66,19 @@ module Yt
59
66
  @headers.each{|name, value| request.add_field name, value}
60
67
  end
61
68
 
69
+ # To receive a gzip-encoded response you must do two things:
70
+ # - Set the Accept-Encoding HTTP request header to gzip.
71
+ # - Modify your user agent to contain the string gzip.
72
+ # Note that HTTP headers are case-insensitive.
73
+ # @see https://developers.google.com/youtube/v3/getting-started#gzip
74
+ # @see http://www.ietf.org/rfc/rfc2616.txt
75
+ def gzip_headers
76
+ @gzip_headers ||= {}.tap do |headers|
77
+ headers['accept-encoding'] = 'gzip'
78
+ headers['user-agent'] = 'Yt (gzip)'
79
+ end
80
+ end
81
+
62
82
  def set_body!(request)
63
83
  case @body_type
64
84
  when :json then request.body = @body.to_json
@@ -157,17 +177,11 @@ module Yt
157
177
  end
158
178
  end
159
179
 
160
- def request_error_message
161
- {}.tap do |message|
162
- message[:request_curl] = as_curl
163
- message[:response_body] = JSON(response.body) rescue response.inspect
164
- end.to_json
165
- end
166
-
167
180
  def as_curl
168
181
  'curl'.tap do |curl|
169
182
  curl << " -X #{http_request.method}"
170
183
  http_request.each_header do |name, value|
184
+ next if gzip_headers.has_key? name
171
185
  curl << %Q{ -H "#{name}: #{value}"}
172
186
  end
173
187
  curl << %Q{ -d '#{http_request.body}'} if http_request.body
@@ -19,6 +19,7 @@ module Yt
19
19
  rescue Yt::Error => error
20
20
  ignorable_errors = error.reasons & ['subscriptionNotFound']
21
21
  raise error unless options[:ignore_errors] && ignorable_errors.any?
22
+ @id = nil
22
23
  end
23
24
  !exists?
24
25
  end
@@ -8,7 +8,7 @@ module Yt
8
8
  # @!attribute [r] details_set
9
9
  # @return [Yt::Models::DetailsSet] the video’s content details.
10
10
  has_one :details_set
11
- delegate :duration, to: :details_set
11
+ delegate :duration, :hd?, :stereoscopic?, :captioned?, :licensed?, to: :details_set
12
12
 
13
13
  # @!attribute [r] rating
14
14
  # @return [Yt::Models::Rating] the video’s rating.
@@ -1,3 +1,3 @@
1
1
  module Yt
2
- VERSION = '0.6.4'
2
+ VERSION = '0.6.5'
3
3
  end
@@ -25,4 +25,52 @@ describe Yt::DetailsSet do
25
25
  it { expect(details_set.duration).to eq 51 }
26
26
  end
27
27
  end
28
+
29
+ describe '#stereoscopic?' do
30
+ context 'given a 3D video' do
31
+ let(:data) { {"dimension"=>"3d"} }
32
+ it { expect(details_set).to be_stereoscopic }
33
+ end
34
+
35
+ context 'given a 2D video' do
36
+ let(:data) { {"dimension"=>"2d"} }
37
+ it { expect(details_set).not_to be_stereoscopic }
38
+ end
39
+ end
40
+
41
+ describe '#hd?' do
42
+ context 'given a high-definition video' do
43
+ let(:data) { {"definition"=>"hd"} }
44
+ it { expect(details_set).to be_hd }
45
+ end
46
+
47
+ context 'given a standard-definition video' do
48
+ let(:data) { {"definition"=>"sd"} }
49
+ it { expect(details_set).not_to be_hd }
50
+ end
51
+ end
52
+
53
+ describe '#captioned?' do
54
+ context 'given a video with captions' do
55
+ let(:data) { {"caption"=>"true"} }
56
+ it { expect(details_set).to be_captioned }
57
+ end
58
+
59
+ context 'given a video without captions' do
60
+ let(:data) { {"caption"=>"false"} }
61
+ it { expect(details_set).not_to be_captioned }
62
+ end
63
+ end
64
+
65
+ describe '#captioned?' do
66
+ context 'given a video with licensed content' do
67
+ let(:data) { {"licensedContent"=>true} }
68
+ it { expect(details_set).to be_licensed }
69
+ end
70
+
71
+ context 'given a video without licensed content' do
72
+ let(:data) { {"licensedContent"=>false} }
73
+ it { expect(details_set).not_to be_licensed }
74
+ end
75
+ end
28
76
  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.6.4
4
+ version: 0.6.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Claudio Baccigalupo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-17 00:00:00.000000000 Z
11
+ date: 2014-06-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport