yt 0.9.5 → 0.9.6

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: a618a834dfa7b3cecfc38f24ea9d7c7f42db9ca3
4
- data.tar.gz: 8136067b0f3568ac059e4eacfe0eb812c3c9c4e2
3
+ metadata.gz: f2401a0d9b81d6da08424943a09b392870081fc6
4
+ data.tar.gz: b1fd60bb4f1426f34182730f73bdf4641e6025d0
5
5
  SHA512:
6
- metadata.gz: adb13cd19177496972a8f43bf663716ce250ca8e0d53d8aa570efe82ae4b5b97371d9697bb3f90bdec1a1aa6d082f13a79096c9af777a70fe6f27e2a577819f9
7
- data.tar.gz: 212188da7ddfd9dd7c17b62c6568ff51e1fcdc55cc63da4b13552bae96140338723a2fce7b82f025273bd3e538405fbb4da81fcf1d678f621feb4fc58da573e3
6
+ metadata.gz: 74acf5be09a43cdbb3f7da60d275c57b5db7fb9336c4f236c0db48257b0120ebb95619a4e5a5ae8eb77a5b6450c600d0cbed14bb015a43e1d2b474c813020caf
7
+ data.tar.gz: 7daada1a1bc24ddd581cacbb6f2171a5947f9c387b608222dae391b664bb944d1c22a8e6d6cbcfd7df3531ae90622e200eae61eaebfbe8bf00c8e333c0475523
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- yt (0.9.5)
4
+ yt (0.9.6)
5
5
  activesupport
6
6
 
7
7
  GEM
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.5'
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
- else item.send(method) == value
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
- # attrs are id and kind
8
- def insert(attrs = {}, options = {}) #
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 channels.
21
- # @see https://developers.google.com/youtube/v3/docs/channels/list
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
@@ -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
- snippet = {keys: [:title, :description, :tags], required: true}
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
- {id: video_id, kind: :video}
80
+ {resource_id: {kind: 'youtube#video', videoId: video_id}}
78
81
  end
79
82
  end
80
83
  end
@@ -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
- body = {}
60
- update_parts.each do |name, part|
61
- body[name] = {}.tap do |hash|
62
- part[:keys].map{|k| hash[camelize k] = attributes.fetch k, send(k)}
63
- end if should_include_part_in_update?(part, attributes)
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
@@ -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: {keys: snippet_keys}, status: {keys: status_keys}}
167
+ {snippet: snippet, status: {keys: status_keys}}
167
168
  end
168
169
  end
169
170
  end
@@ -1,3 +1,3 @@
1
1
  module Yt
2
- VERSION = '0.9.5'
2
+ VERSION = '0.9.6'
3
3
  end
@@ -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
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.5
4
+ version: 0.9.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Claudio Baccigalupo