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 +4 -4
- data/Gemfile.lock +1 -1
- data/HISTORY.md +1 -0
- data/README.md +5 -1
- data/TODO.md +53 -8
- data/bin/yt +4 -0
- data/lib/yt/actions/delete_all.rb +2 -2
- data/lib/yt/actions/list.rb +10 -3
- data/lib/yt/collections/reports.rb +4 -3
- data/lib/yt/collections/subscriptions.rb +1 -1
- data/lib/yt/models/channel.rb +1 -1
- data/lib/yt/models/details_set.rb +25 -4
- data/lib/yt/models/playlist.rb +1 -1
- data/lib/yt/models/playlist_item.rb +1 -1
- data/lib/yt/models/request.rb +22 -8
- data/lib/yt/models/subscription.rb +1 -0
- data/lib/yt/models/video.rb +1 -1
- data/lib/yt/version.rb +1 -1
- data/spec/models/details_set_spec.rb +48 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8c7f28e1adc91466df73429cd2e12988092acabd
|
4
|
+
data.tar.gz: a66cb8c64a3764ffcad1e1988fa025ca5a9d5094
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b422e2ac62121f98113de5a65f53c2925009ddc3dc78737ffa9c145427201eb53df3723ebe0cdde108f5dfcfa05655c3bea9413ec03309e363075214a01b760a
|
7
|
+
data.tar.gz: 90bcf64d69cbb1161f694d22b5782cedcc0668f34025824fdea4da2e396af80a28b263abf9f52b0508cf14f7fe14c8f75ae49788cdc520e6b0395d9e5f4ada08
|
data/Gemfile.lock
CHANGED
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.
|
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
|
-
|
5
|
-
|
4
|
+
List of supported methods
|
5
|
+
=========================
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
* ENV support
|
7
|
+
YouTube Data API V3 (https://developers.google.com/youtube/v3/docs)
|
8
|
+
-------------------------------------------------------------------
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
data/lib/yt/actions/list.rb
CHANGED
@@ -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
|
-
|
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
|
|
data/lib/yt/models/channel.rb
CHANGED
@@ -4,7 +4,7 @@ require 'yt/associations/views'
|
|
4
4
|
|
5
5
|
module Yt
|
6
6
|
module Models
|
7
|
-
#
|
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
|
6
|
-
#
|
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
|
14
|
+
# @return [Integer] the duration of the video (in seconds).
|
15
15
|
def duration
|
16
|
-
@duration
|
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
|
data/lib/yt/models/playlist.rb
CHANGED
@@ -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
|
data/lib/yt/models/request.rb
CHANGED
@@ -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
|
data/lib/yt/models/video.rb
CHANGED
@@ -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.
|
data/lib/yt/version.rb
CHANGED
@@ -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
|
+
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-
|
11
|
+
date: 2014-06-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|