yt 0.9.5 → 0.9.6
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/Gemfile.lock +1 -1
- data/HISTORY.md +1 -0
- data/README.md +3 -3
- data/lib/yt/actions/delete_all.rb +3 -1
- data/lib/yt/collections/playlist_items.rb +8 -8
- data/lib/yt/collections/playlists.rb +6 -14
- data/lib/yt/collections/resources.rb +56 -0
- data/lib/yt/models/playlist.rb +5 -2
- data/lib/yt/models/resource.rb +28 -6
- data/lib/yt/models/video.rb +2 -1
- data/lib/yt/version.rb +1 -1
- data/spec/requests/as_account/channel_spec.rb +3 -3
- data/spec/requests/as_account/playlist_spec.rb +11 -0
- data/spec/requests/as_account/video_spec.rb +11 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f2401a0d9b81d6da08424943a09b392870081fc6
|
4
|
+
data.tar.gz: b1fd60bb4f1426f34182730f73bdf4641e6025d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 74acf5be09a43cdbb3f7da60d275c57b5db7fb9336c4f236c0db48257b0120ebb95619a4e5a5ae8eb77a5b6450c600d0cbed14bb015a43e1d2b474c813020caf
|
7
|
+
data.tar.gz: 7daada1a1bc24ddd581cacbb6f2171a5947f9c387b608222dae391b664bb944d1c22a8e6d6cbcfd7df3531ae90622e200eae61eaebfbe8bf00c8e333c0475523
|
data/Gemfile.lock
CHANGED
data/HISTORY.md
CHANGED
@@ -8,6 +8,7 @@ v0.9 - 2014/07/28
|
|
8
8
|
* Add claim.third_party?
|
9
9
|
* Add actual_start_time, actual_end_time, scheduled_start_time, scheduled_end_time for live-streaming videos
|
10
10
|
* Add privacy_status, public_stats_viewable, publish_at to the options that Video#update accepts
|
11
|
+
* Allow angle brackets when editing title, description, tags and replace them with similar characters allowed by YouTube
|
11
12
|
|
12
13
|
v0.8 - 2014/07/18
|
13
14
|
-----------------
|
data/README.md
CHANGED
@@ -41,7 +41,7 @@ To install on your system, run
|
|
41
41
|
|
42
42
|
To use inside a bundled Ruby project, add this line to the Gemfile:
|
43
43
|
|
44
|
-
gem 'yt', '~> 0.9.
|
44
|
+
gem 'yt', '~> 0.9.6'
|
45
45
|
|
46
46
|
Since the gem follows [Semantic Versioning](http://semver.org),
|
47
47
|
indicating the full version in your Gemfile (~> *major*.*minor*.*patch*)
|
@@ -287,7 +287,7 @@ video.like #=> true
|
|
287
287
|
account = Yt::Account.new access_token: 'ya29.1.ABCDEFGHIJ'
|
288
288
|
video = Yt::Video.new id: 'MESycYJytkU', auth: account
|
289
289
|
|
290
|
-
video.update title: 'A title', description: 'A description', tags: ['a tag'], categoryId: '21'
|
290
|
+
video.update title: 'A title', description: 'A description <with angle brackets>', tags: ['a tag'], categoryId: '21'
|
291
291
|
|
292
292
|
video.views since: 7.days.ago #=> {Wed, 28 May 2014 => 12.0, Thu, 29 May 2014 => 3.0, …}
|
293
293
|
video.comments until: 2.days.ago #=> {Wed, 28 May 2014 => 9.0, Thu, 29 May 2014 => 4.0, …}
|
@@ -353,7 +353,7 @@ playlist.playlist_items.first #=> #<Yt::Models::PlaylistItem @id=...>
|
|
353
353
|
*The methods above do not require authentication.*
|
354
354
|
|
355
355
|
```ruby
|
356
|
-
playlist.update title: 'title', description: 'desc', tags: ['new tag'], privacy_status: 'private'
|
356
|
+
playlist.update title: 'A <title> with angle brackets', description: 'desc', tags: ['new tag'], privacy_status: 'private'
|
357
357
|
playlist.add_video 'MESycYJytkU'
|
358
358
|
playlist.add_videos ['MESycYJytkU', 'MESycYJytkU']
|
359
359
|
playlist.delete_playlist_items title: 'Fullscreen Creator Platform' #=> [true]
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
require 'yt/actions/list'
|
2
3
|
require 'yt/models/request'
|
3
4
|
|
@@ -20,7 +21,8 @@ module Yt
|
|
20
21
|
# TODO: could be symbol etc...
|
21
22
|
item.respond_to?(method) && case value
|
22
23
|
when Regexp then item.send(method) =~ value
|
23
|
-
|
24
|
+
when Array then item.send(method) == value.map{|item| item.to_s.gsub('<', '‹').gsub('>', '›')}
|
25
|
+
else item.send(method) == value.to_s.gsub('<', '‹').gsub('>', '›')
|
24
26
|
end
|
25
27
|
end
|
26
28
|
end
|
@@ -4,12 +4,8 @@ module Yt
|
|
4
4
|
module Collections
|
5
5
|
class PlaylistItems < Resources
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
resource = {kind: "youtube##{attrs[:kind]}"}
|
10
|
-
resource["#{attrs[:kind]}Id"] = attrs[:id]
|
11
|
-
snippet = {playlistId: @parent.id, resourceId: resource}
|
12
|
-
do_insert body: {snippet: snippet}, params: {part: 'snippet,status'}
|
7
|
+
def insert(attributes = {}, options = {})
|
8
|
+
super attributes.merge(playlist_id: @parent.id), options
|
13
9
|
rescue Yt::Error => error
|
14
10
|
ignorable_errors = error.reasons & ['videoNotFound', 'forbidden']
|
15
11
|
raise error unless options[:ignore_errors] && ignorable_errors.any?
|
@@ -17,8 +13,8 @@ module Yt
|
|
17
13
|
|
18
14
|
private
|
19
15
|
|
20
|
-
# @return [Hash] the parameters to submit to YouTube to list
|
21
|
-
# @see https://developers.google.com/youtube/v3/docs/
|
16
|
+
# @return [Hash] the parameters to submit to YouTube to list playlist items.
|
17
|
+
# @see https://developers.google.com/youtube/v3/docs/playlistItems/list
|
22
18
|
def list_params
|
23
19
|
super.tap{|params| params[:params] = playlist_items_params}
|
24
20
|
end
|
@@ -26,6 +22,10 @@ module Yt
|
|
26
22
|
def playlist_items_params
|
27
23
|
resources_params.merge playlist_id: @parent.id
|
28
24
|
end
|
25
|
+
|
26
|
+
def insert_parts
|
27
|
+
{snippet: {keys: [:playlist_id, :resource_id]}}
|
28
|
+
end
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
@@ -4,20 +4,6 @@ module Yt
|
|
4
4
|
module Collections
|
5
5
|
class Playlists < Resources
|
6
6
|
|
7
|
-
# Valid body (no defaults) are: title (string), description (string), privacy_status (string),
|
8
|
-
# tags (array of strings)
|
9
|
-
def insert(options = {})
|
10
|
-
body = {}
|
11
|
-
|
12
|
-
snippet = options.slice :title, :description, :tags
|
13
|
-
body[:snippet] = snippet if snippet.any?
|
14
|
-
|
15
|
-
status = options[:privacy_status]
|
16
|
-
body[:status] = {privacyStatus: status} if status
|
17
|
-
|
18
|
-
do_insert body: body, params: {part: 'snippet,status'}
|
19
|
-
end
|
20
|
-
|
21
7
|
private
|
22
8
|
|
23
9
|
# @return [Hash] the parameters to submit to YouTube to list channels.
|
@@ -29,6 +15,12 @@ module Yt
|
|
29
15
|
def playlists_params
|
30
16
|
resources_params.merge channel_id: @parent.id
|
31
17
|
end
|
18
|
+
|
19
|
+
def insert_parts
|
20
|
+
snippet = {keys: [:title, :description, :tags], sanitize_brackets: true}
|
21
|
+
status = {keys: [:privacy_status]}
|
22
|
+
{snippet: snippet, status: status}
|
23
|
+
end
|
32
24
|
end
|
33
25
|
end
|
34
26
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
require 'yt/collections/base'
|
2
3
|
|
3
4
|
module Yt
|
@@ -7,6 +8,13 @@ module Yt
|
|
7
8
|
do_delete_all params
|
8
9
|
end
|
9
10
|
|
11
|
+
def insert(attributes = {}, options = {}) #
|
12
|
+
underscore_keys! attributes
|
13
|
+
body = build_insert_body attributes
|
14
|
+
params = {part: body.keys.join(',')}
|
15
|
+
do_insert(params: params, body: body)
|
16
|
+
end
|
17
|
+
|
10
18
|
private
|
11
19
|
|
12
20
|
# @return [resource_class] a new resource item initialized with
|
@@ -27,6 +35,54 @@ module Yt
|
|
27
35
|
require "yt/models/#{resource_name.underscore}"
|
28
36
|
"Yt::Models::#{resource_name}".constantize
|
29
37
|
end
|
38
|
+
|
39
|
+
def build_insert_body(attributes = {})
|
40
|
+
{}.tap do |body|
|
41
|
+
insert_parts.each do |name, part|
|
42
|
+
if should_include_part_in_insert? part, attributes
|
43
|
+
body[name] = build_insert_body_part part, attributes
|
44
|
+
sanitize_brackets! body[name] if part[:sanitize_brackets]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def build_insert_body_part(part, attributes = {})
|
51
|
+
{}.tap do |body_part|
|
52
|
+
part[:keys].map do |key|
|
53
|
+
body_part[camelize key] = attributes[key]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def should_include_part_in_insert?(part, attributes = {})
|
59
|
+
(part[:keys] & attributes.keys).any?
|
60
|
+
end
|
61
|
+
|
62
|
+
# If we dropped support for ActiveSupport 3, then we could simply
|
63
|
+
# invoke transform_keys!{|key| key.to_s.underscore.to_sym}
|
64
|
+
def underscore_keys!(hash)
|
65
|
+
hash.dup.each_key{|key| hash[underscore key] = hash.delete key}
|
66
|
+
end
|
67
|
+
|
68
|
+
# @return [Hash] the original hash with angle brackets characters in its
|
69
|
+
# values replaced with similar Unicode characters accepted by Youtube.
|
70
|
+
# @see https://support.google.com/youtube/answer/57404?hl=en
|
71
|
+
def sanitize_brackets!(source)
|
72
|
+
case source
|
73
|
+
when String then source.gsub('<', '‹').gsub('>', '›')
|
74
|
+
when Array then source.map{|string| sanitize_brackets! string}
|
75
|
+
when Hash then source.each{|k,v| source[k] = sanitize_brackets! v}
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def camelize(value)
|
80
|
+
value.to_s.camelize(:lower).to_sym
|
81
|
+
end
|
82
|
+
|
83
|
+
def underscore(value)
|
84
|
+
value.to_s.underscore.to_sym
|
85
|
+
end
|
30
86
|
end
|
31
87
|
end
|
32
88
|
end
|
data/lib/yt/models/playlist.rb
CHANGED
@@ -68,13 +68,16 @@ module Yt
|
|
68
68
|
|
69
69
|
# @see https://developers.google.com/youtube/v3/docs/playlists/update
|
70
70
|
def update_parts
|
71
|
-
|
71
|
+
keys = [:title, :description, :tags]
|
72
|
+
snippet = {keys: keys, required: true, sanitize_brackets: true}
|
72
73
|
status = {keys: [:privacy_status]}
|
73
74
|
{snippet: snippet, status: status}
|
74
75
|
end
|
75
76
|
|
77
|
+
# @todo: extend camelize to also camelize the nested hashes, so we
|
78
|
+
# don’t have to write videoId
|
76
79
|
def video_params(video_id)
|
77
|
-
{
|
80
|
+
{resource_id: {kind: 'youtube#video', videoId: video_id}}
|
78
81
|
end
|
79
82
|
end
|
80
83
|
end
|
data/lib/yt/models/resource.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
require 'yt/models/base'
|
2
4
|
require 'yt/models/url'
|
3
5
|
|
@@ -56,13 +58,22 @@ module Yt
|
|
56
58
|
end
|
57
59
|
|
58
60
|
def build_update_body(attributes = {})
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
61
|
+
{}.tap do |body|
|
62
|
+
update_parts.each do |name, part|
|
63
|
+
if should_include_part_in_update? part, attributes
|
64
|
+
body[name] = build_update_body_part part, attributes
|
65
|
+
sanitize_brackets! body[name] if part[:sanitize_brackets]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def build_update_body_part(part, attributes = {})
|
72
|
+
{}.tap do |body_part|
|
73
|
+
part[:keys].map do |key|
|
74
|
+
body_part[camelize key] = attributes.fetch key, send(key)
|
75
|
+
end
|
64
76
|
end
|
65
|
-
body
|
66
77
|
end
|
67
78
|
|
68
79
|
def should_include_part_in_update?(part, attributes = {})
|
@@ -75,6 +86,17 @@ module Yt
|
|
75
86
|
hash.dup.each_key{|key| hash[underscore key] = hash.delete key}
|
76
87
|
end
|
77
88
|
|
89
|
+
# @return [Hash] the original hash with angle brackets characters in its
|
90
|
+
# values replaced with similar Unicode characters accepted by Youtube.
|
91
|
+
# @see https://support.google.com/youtube/answer/57404?hl=en
|
92
|
+
def sanitize_brackets!(source)
|
93
|
+
case source
|
94
|
+
when String then source.gsub('<', '‹').gsub('>', '›')
|
95
|
+
when Array then source.map{|string| sanitize_brackets! string}
|
96
|
+
when Hash then source.each{|k,v| source[k] = sanitize_brackets! v}
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
78
100
|
def camelize(value)
|
79
101
|
value.to_s.camelize(:lower).to_sym
|
80
102
|
end
|
data/lib/yt/models/video.rb
CHANGED
@@ -161,9 +161,10 @@ module Yt
|
|
161
161
|
# @todo: Add recording details keys
|
162
162
|
def update_parts
|
163
163
|
snippet_keys = [:title, :description, :tags, :category_id]
|
164
|
+
snippet = {keys: snippet_keys, sanitize_brackets: true}
|
164
165
|
status_keys = [:privacy_status, :embeddable, :license,
|
165
166
|
:public_stats_viewable, :publish_at]
|
166
|
-
{snippet:
|
167
|
+
{snippet: snippet, status: {keys: status_keys}}
|
167
168
|
end
|
168
169
|
end
|
169
170
|
end
|
data/lib/yt/version.rb
CHANGED
@@ -54,9 +54,9 @@ describe Yt::Channel, :device_app do
|
|
54
54
|
|
55
55
|
context 'given my own channel' do
|
56
56
|
let(:id) { $account.channel.id }
|
57
|
-
let(:title) { 'Yt Test title' }
|
58
|
-
let(:description) { 'Yt Test description' }
|
59
|
-
let(:tags) { ['Yt Test Tag 1', 'Yt Test Tag 2'] }
|
57
|
+
let(:title) { 'Yt Test <title>' }
|
58
|
+
let(:description) { 'Yt Test <description>' }
|
59
|
+
let(:tags) { ['Yt Test Tag 1', 'Yt Test <Tag> 2'] }
|
60
60
|
let(:privacy_status) { 'unlisted' }
|
61
61
|
let(:params) { {title: title, description: description, tags: tags, privacy_status: privacy_status} }
|
62
62
|
|
@@ -91,6 +91,17 @@ describe Yt::Playlist, :device_app do
|
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
94
|
+
context 'given I update title, description and/or tags using angle brackets' do
|
95
|
+
let(:attrs) { {title: "Yt Test < >", description: '< >', tags: ['<tag>']} }
|
96
|
+
|
97
|
+
specify 'updates them replacing angle brackets with similar unicode characters accepted by YouTube' do
|
98
|
+
expect(update).to be true
|
99
|
+
expect(playlist.title).to eq 'Yt Test ‹ ›'
|
100
|
+
expect(playlist.description).to eq '‹ ›'
|
101
|
+
expect(playlist.tags).to eq ['‹tag›']
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
94
105
|
context 'given I update the privacy status' do
|
95
106
|
let!(:new_privacy_status) { old_privacy_status == 'private' ? 'unlisted' : 'private' }
|
96
107
|
|
@@ -194,6 +194,17 @@ describe Yt::Video, :device_app do
|
|
194
194
|
end
|
195
195
|
end
|
196
196
|
|
197
|
+
context 'given I update title, description and/or tags using angle brackets' do
|
198
|
+
let(:attrs) { {title: "Example Yt Test < >", description: '< >', tags: ['<tag>']} }
|
199
|
+
|
200
|
+
specify 'updates them replacing angle brackets with similar unicode characters accepted by YouTube' do
|
201
|
+
expect(update).to be true
|
202
|
+
expect(video.title).to eq 'Example Yt Test ‹ ›'
|
203
|
+
expect(video.description).to eq '‹ ›'
|
204
|
+
expect(video.tags).to eq ['‹tag›']
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
197
208
|
# note: 'scheduled' videos cannot be set to 'unlisted'
|
198
209
|
context 'given I update the privacy status' do
|
199
210
|
before { video.update publish_at: nil if video.scheduled? }
|
@@ -347,5 +358,4 @@ describe Yt::Video, :device_app do
|
|
347
358
|
end
|
348
359
|
end
|
349
360
|
end
|
350
|
-
|
351
361
|
end
|