yt 0.6.4 → 0.6.5

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 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