yt 0.25.17 → 0.25.18
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/lib/yt.rb +2 -0
- data/lib/yt/actions/list.rb +1 -1
- data/lib/yt/collections/group_infos.rb +26 -0
- data/lib/yt/collections/video_groups.rb +28 -0
- data/lib/yt/constants/geography.rb +323 -0
- data/lib/yt/models/account.rb +12 -0
- data/lib/yt/models/content_owner.rb +12 -0
- data/lib/yt/models/group_info.rb +16 -0
- data/lib/yt/models/video_group.rb +127 -0
- data/lib/yt/request.rb +2 -1
- data/lib/yt/version.rb +1 -1
- data/spec/constants/geography_spec.rb +16 -0
- data/spec/models/request_spec.rb +21 -0
- data/spec/requests/as_account/account_spec.rb +15 -0
- data/spec/requests/as_content_owner/content_owner_spec.rb +14 -0
- data/spec/requests/as_content_owner/video_group_spec.rb +66 -0
- data/spec/spec_helper.rb +1 -1
- metadata +11 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 326f3adf4a4e1e7bbf64930125f77a404276d391
|
4
|
+
data.tar.gz: 26c77d99c92fc26b67b085bb1a453dc297f95a90
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c07e83a315d72de93ec39e4c24b953b7aa65f96cfa7fda272d0f6bc7f18819ba065a407374aef07571b811c5baed4c4bd993c3895c19d39c3d54a0c9eb6c7291
|
7
|
+
data.tar.gz: 17cab126cf09804f07a3025f4daab542ae0a5cbb54ee6026953ec9e67e53784b972560fefd74cb66e5c629808c28114adf9080379e820bba7bf8c51cdac9ce8b
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,14 @@ For more information about changelogs, check
|
|
6
6
|
[Keep a Changelog](http://keepachangelog.com) and
|
7
7
|
[Vandamme](http://tech-angels.github.io/vandamme).
|
8
8
|
|
9
|
+
## 0.25.18 - 2016-01-08
|
10
|
+
|
11
|
+
* [FEATURE] Add Yt::COUNTRIES and Yt::US_STATES
|
12
|
+
* [FEATURE] Add YouTube Analytics Video Groups
|
13
|
+
* [FEATURE] Add `:video_groups` to Yt::Account (list video-groups created by an account)
|
14
|
+
* [FEATURE] Add `:video_groups` to Yt::ContentOwner (list video-groups on behalf of a content owner)
|
15
|
+
* [FEATURE] Add reports by video-group
|
16
|
+
|
9
17
|
## 0.25.17 - 2016-01-05
|
10
18
|
|
11
19
|
* [FEATURE] Add `:videos` to Yt::ContentOwner to list videos in network with a content owner
|
data/lib/yt.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'yt/config'
|
2
2
|
require 'yt/version'
|
3
|
+
require 'yt/constants/geography'
|
3
4
|
require 'yt/models/account'
|
4
5
|
require 'yt/models/channel'
|
5
6
|
require 'yt/models/claim'
|
@@ -9,6 +10,7 @@ require 'yt/models/match_policy'
|
|
9
10
|
require 'yt/models/playlist'
|
10
11
|
require 'yt/models/playlist_item'
|
11
12
|
require 'yt/models/video'
|
13
|
+
require 'yt/models/video_group'
|
12
14
|
require 'yt/models/ownership'
|
13
15
|
require 'yt/models/advertising_options_set'
|
14
16
|
|
data/lib/yt/actions/list.rb
CHANGED
@@ -47,7 +47,7 @@ module Yt
|
|
47
47
|
def find_next
|
48
48
|
@items ||= []
|
49
49
|
if @items[@last_index].nil? && more_pages?
|
50
|
-
more_items = next_page.map{|data| new_item data}
|
50
|
+
more_items = next_page.map{|data| new_item data}.compact
|
51
51
|
@items.concat more_items
|
52
52
|
end
|
53
53
|
@items[(@last_index +=1) -1]
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'yt/collections/base'
|
2
|
+
require 'yt/models/snippet'
|
3
|
+
|
4
|
+
module Yt
|
5
|
+
module Collections
|
6
|
+
# @private
|
7
|
+
class GroupInfos < Base
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def attributes_for_new_item(data)
|
12
|
+
{data: data, auth: @auth}
|
13
|
+
end
|
14
|
+
|
15
|
+
def list_params
|
16
|
+
super.tap do |params|
|
17
|
+
params[:path] = "/youtube/analytics/v1/groups"
|
18
|
+
params[:params] = {id: @parent.id}
|
19
|
+
if @auth.owner_name
|
20
|
+
params[:params][:on_behalf_of_content_owner] = @auth.owner_name
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'yt/collections/base'
|
2
|
+
require 'yt/models/video_group'
|
3
|
+
require 'yt/models/group_info'
|
4
|
+
|
5
|
+
module Yt
|
6
|
+
module Collections
|
7
|
+
# @private
|
8
|
+
class VideoGroups < Base
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def attributes_for_new_item(data)
|
13
|
+
{id: data['id'], auth: @auth, group_info: Yt::GroupInfo.new(data: data)}
|
14
|
+
end
|
15
|
+
|
16
|
+
def new_item(data)
|
17
|
+
super if data['contentDetails']['itemType'] == 'youtube#video'
|
18
|
+
end
|
19
|
+
|
20
|
+
def list_params
|
21
|
+
super.tap do |params|
|
22
|
+
params[:path] = "/youtube/analytics/v1/groups"
|
23
|
+
params[:params] = @parent.video_groups_params
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,323 @@
|
|
1
|
+
module Yt
|
2
|
+
# The list of country codes and names used by the YouTube Analytics API.
|
3
|
+
# @see https://developers.google.com/youtube/analytics/v1/dimsmets/dims#country
|
4
|
+
COUNTRIES = {
|
5
|
+
AC: 'Ascension',
|
6
|
+
AD: 'Andorra',
|
7
|
+
AE: 'United Arab Emirates',
|
8
|
+
AF: 'Afghanistan',
|
9
|
+
AG: 'Antigua and Barbuda',
|
10
|
+
AI: 'Anguilla',
|
11
|
+
AL: 'Albania',
|
12
|
+
AM: 'Armenia',
|
13
|
+
AN: 'Netherlands Antilles',
|
14
|
+
AO: 'Angola',
|
15
|
+
AQ: 'Antarctic Territory',
|
16
|
+
AR: 'Argentina',
|
17
|
+
AS: 'American Samoa',
|
18
|
+
AT: 'Austria',
|
19
|
+
AU: 'Australia',
|
20
|
+
AW: 'Aruba',
|
21
|
+
AX: 'Aland',
|
22
|
+
AZ: 'Azerbaijan',
|
23
|
+
BA: 'Bosnia and Herzegovina',
|
24
|
+
BB: 'Barbados',
|
25
|
+
BD: 'Bangladesh',
|
26
|
+
BE: 'Belgium',
|
27
|
+
BF: 'Burkina Faso',
|
28
|
+
BG: 'Bulgaria',
|
29
|
+
BH: 'Bahrain',
|
30
|
+
BI: 'Burundi',
|
31
|
+
BJ: 'Benin',
|
32
|
+
BL: 'Saint Barthélemy',
|
33
|
+
BM: 'Bermuda',
|
34
|
+
BN: 'Brunei',
|
35
|
+
BO: 'Bolivia',
|
36
|
+
BQ: 'Bonaire, Sint Eustatius and Saba',
|
37
|
+
BR: 'Brazil',
|
38
|
+
BS: 'Bahamas',
|
39
|
+
BT: 'Bhutan',
|
40
|
+
BV: 'Bouvet Island',
|
41
|
+
BW: 'Botswana',
|
42
|
+
BY: 'Belarus',
|
43
|
+
BZ: 'Belize',
|
44
|
+
CA: 'Canada',
|
45
|
+
CC: 'Cocos (Keeling) Islands',
|
46
|
+
CD: 'Congo',
|
47
|
+
CF: 'Central African Republic',
|
48
|
+
CG: 'Congo',
|
49
|
+
CH: 'Switzerland',
|
50
|
+
CI: 'Ivory Coast',
|
51
|
+
CK: 'Cook Islands',
|
52
|
+
CL: 'Chile',
|
53
|
+
CM: 'Cameroon',
|
54
|
+
CN: 'China',
|
55
|
+
CO: 'Colombia',
|
56
|
+
CR: 'Costa Rica',
|
57
|
+
CU: 'Cuba',
|
58
|
+
CV: 'Cape Verde',
|
59
|
+
CW: 'Curaçao',
|
60
|
+
CX: 'Christmas Island',
|
61
|
+
CY: 'Cyprus',
|
62
|
+
CZ: 'Czech Republic',
|
63
|
+
DE: 'Germany',
|
64
|
+
DJ: 'Djibouti',
|
65
|
+
DK: 'Denmark',
|
66
|
+
DM: 'Dominica',
|
67
|
+
DO: 'Dominican Republic',
|
68
|
+
DZ: 'Algeria',
|
69
|
+
EC: 'Ecuador',
|
70
|
+
EE: 'Estonia',
|
71
|
+
EG: 'Egypt',
|
72
|
+
EH: 'Western Sahara',
|
73
|
+
ER: 'Eritrea',
|
74
|
+
ES: 'Spain',
|
75
|
+
ET: 'Ethiopia',
|
76
|
+
FI: 'Finland',
|
77
|
+
FJ: 'Fiji',
|
78
|
+
FK: 'Falkland Islands',
|
79
|
+
FM: 'Micronesia',
|
80
|
+
FO: 'Faroe Islands',
|
81
|
+
FR: 'France',
|
82
|
+
GA: 'Gabon',
|
83
|
+
GB: 'United Kingdom',
|
84
|
+
GD: 'Grenada',
|
85
|
+
GE: 'Georgia',
|
86
|
+
GF: 'French Guiana',
|
87
|
+
GG: 'Guernsey',
|
88
|
+
GH: 'Ghana',
|
89
|
+
GI: 'Gibraltar',
|
90
|
+
GL: 'Greenland',
|
91
|
+
GM: 'Gambia',
|
92
|
+
GN: 'Guinea',
|
93
|
+
GP: 'Guadeloupe',
|
94
|
+
GQ: 'Equatorial Guinea',
|
95
|
+
GR: 'Greece',
|
96
|
+
GS: 'South Georgia & South Sandwich Islands',
|
97
|
+
GT: 'Guatemala',
|
98
|
+
GU: 'Guam',
|
99
|
+
GW: 'Guinea-Bissau',
|
100
|
+
GY: 'Guyana',
|
101
|
+
HK: 'Hong Kong',
|
102
|
+
HM: 'Heard Island and McDonald Islands',
|
103
|
+
HN: 'Honduras',
|
104
|
+
HR: 'Croatia',
|
105
|
+
HT: 'Haiti',
|
106
|
+
HU: 'Hungary',
|
107
|
+
ID: 'Indonesia',
|
108
|
+
IE: 'Ireland',
|
109
|
+
IL: 'Israel',
|
110
|
+
IM: 'Isle of Man',
|
111
|
+
IN: 'India',
|
112
|
+
IO: 'British Indian Ocean Territory',
|
113
|
+
IQ: 'Iraq',
|
114
|
+
IR: 'Iran',
|
115
|
+
IS: 'Iceland',
|
116
|
+
IT: 'Italy',
|
117
|
+
JE: 'Jersey',
|
118
|
+
JM: 'Jamaica',
|
119
|
+
JO: 'Jordan',
|
120
|
+
JP: 'Japan',
|
121
|
+
KE: 'Kenya',
|
122
|
+
KG: 'Kyrgyzstan',
|
123
|
+
KH: 'Cambodia',
|
124
|
+
KI: 'Kiribati',
|
125
|
+
KM: 'Comoros',
|
126
|
+
KN: 'Saint Kitts and Nevis',
|
127
|
+
KP: 'North Korea',
|
128
|
+
KR: 'South Korea',
|
129
|
+
KW: 'Kuwait',
|
130
|
+
KY: 'Cayman Islands',
|
131
|
+
KZ: 'Kazakhstan',
|
132
|
+
LA: 'Laos',
|
133
|
+
LB: 'Lebanon',
|
134
|
+
LC: 'Saint Lucia',
|
135
|
+
LI: 'Liechtenstein',
|
136
|
+
LK: 'Sri Lanka',
|
137
|
+
LR: 'Liberia',
|
138
|
+
LS: 'Lesotho',
|
139
|
+
LT: 'Lithuania',
|
140
|
+
LU: 'Luxembourg',
|
141
|
+
LV: 'Latvia',
|
142
|
+
LY: 'Libya',
|
143
|
+
MA: 'Morocco',
|
144
|
+
MC: 'Monaco',
|
145
|
+
MD: 'Moldova',
|
146
|
+
ME: 'Montenegro',
|
147
|
+
MF: 'Saint Martin',
|
148
|
+
MG: 'Madagascar',
|
149
|
+
MH: 'Marshall Islands',
|
150
|
+
MK: 'Macedonia',
|
151
|
+
ML: 'Mali',
|
152
|
+
MM: 'Myanmar',
|
153
|
+
MN: 'Mongolia',
|
154
|
+
MO: 'Macau',
|
155
|
+
MP: 'Northern Mariana Islands',
|
156
|
+
MQ: 'Martinique',
|
157
|
+
MR: 'Mauritania',
|
158
|
+
MS: 'Montserrat',
|
159
|
+
MT: 'Malta',
|
160
|
+
MU: 'Mauritius',
|
161
|
+
MV: 'Maldives',
|
162
|
+
MW: 'Malawi',
|
163
|
+
MX: 'Mexico',
|
164
|
+
MY: 'Malaysia',
|
165
|
+
MZ: 'Mozambique',
|
166
|
+
NA: 'Namibia',
|
167
|
+
NC: 'New Caledonia',
|
168
|
+
NE: 'Niger',
|
169
|
+
NF: 'Norfolk Island',
|
170
|
+
NG: 'Nigeria',
|
171
|
+
NI: 'Nicaragua',
|
172
|
+
NL: 'Netherlands',
|
173
|
+
NO: 'Norway',
|
174
|
+
NP: 'Nepal',
|
175
|
+
NR: 'Nauru',
|
176
|
+
NU: 'Niue',
|
177
|
+
NZ: 'New Zealand',
|
178
|
+
OM: 'Oman',
|
179
|
+
PA: 'Panama',
|
180
|
+
PE: 'Peru',
|
181
|
+
PF: 'French Polynesia',
|
182
|
+
PG: 'Papua New Guinea',
|
183
|
+
PH: 'Philippines',
|
184
|
+
PK: 'Pakistan',
|
185
|
+
PL: 'Poland',
|
186
|
+
PM: 'Saint Pierre and Miquelon',
|
187
|
+
PN: 'Pitcairn Islands',
|
188
|
+
PR: 'Puerto Rico',
|
189
|
+
PS: 'Palestinian Territory',
|
190
|
+
PT: 'Portugal',
|
191
|
+
PW: 'Palau',
|
192
|
+
PY: 'Paraguay',
|
193
|
+
QA: 'Qatar',
|
194
|
+
RE: 'Reunion',
|
195
|
+
RO: 'Romania',
|
196
|
+
RS: 'Serbia',
|
197
|
+
RU: 'Russia',
|
198
|
+
RW: 'Rwanda',
|
199
|
+
SA: 'Saudi Arabia',
|
200
|
+
SB: 'Solomon Islands',
|
201
|
+
SC: 'Seychelles',
|
202
|
+
SD: 'Sudan',
|
203
|
+
SE: 'Sweden',
|
204
|
+
SG: 'Singapore',
|
205
|
+
SH: 'Saint Helena',
|
206
|
+
SI: 'Slovenia',
|
207
|
+
SJ: 'Svalbard',
|
208
|
+
SK: 'Slovakia',
|
209
|
+
SL: 'Sierra Leone',
|
210
|
+
SM: 'San Marino',
|
211
|
+
SN: 'Senegal',
|
212
|
+
SO: 'Somalia',
|
213
|
+
SR: 'Suriname',
|
214
|
+
SS: 'South Sudan',
|
215
|
+
ST: 'Sao Tome and Principe',
|
216
|
+
SV: 'El Salvador',
|
217
|
+
SX: 'Sint Maarten',
|
218
|
+
SY: 'Syria',
|
219
|
+
SZ: 'Swaziland',
|
220
|
+
TA: 'Tristan da Cunha',
|
221
|
+
TC: 'Turks and Caicos Islands',
|
222
|
+
TD: 'Chad',
|
223
|
+
TF: 'French Southern and Antarctic Lands',
|
224
|
+
TG: 'Togo',
|
225
|
+
TH: 'Thailand',
|
226
|
+
TJ: 'Tajikistan',
|
227
|
+
TK: 'Tokelau',
|
228
|
+
TL: 'East Timor',
|
229
|
+
TM: 'Turkmenistan',
|
230
|
+
TN: 'Tunisia',
|
231
|
+
TO: 'Tonga',
|
232
|
+
TR: 'Turkey',
|
233
|
+
TT: 'Trinidad and Tobago',
|
234
|
+
TV: 'Tuvalu',
|
235
|
+
TW: 'Taiwan',
|
236
|
+
TZ: 'Tanzania',
|
237
|
+
UA: 'Ukraine',
|
238
|
+
UG: 'Uganda',
|
239
|
+
UM: 'Midway Islands',
|
240
|
+
US: 'United States',
|
241
|
+
UY: 'Uruguay',
|
242
|
+
UZ: 'Uzbekistan',
|
243
|
+
VA: 'Vatican City',
|
244
|
+
VC: 'Saint Vincent and the Grenadines',
|
245
|
+
VE: 'Venezuela',
|
246
|
+
VG: 'British Virgin Islands',
|
247
|
+
VI: 'U.S. Virgin Islands',
|
248
|
+
VN: 'Vietnam',
|
249
|
+
VU: 'Vanuatu',
|
250
|
+
XK: 'Kosovo',
|
251
|
+
WF: 'Wallis and Futuna',
|
252
|
+
WS: 'Samoa',
|
253
|
+
YE: 'Yemen',
|
254
|
+
YT: 'Mayotte',
|
255
|
+
ZA: 'South Africa',
|
256
|
+
ZM: 'Zambia',
|
257
|
+
ZW: 'Zimbabwe',
|
258
|
+
ZZ: 'Unknown Region'
|
259
|
+
}.with_indifferent_access
|
260
|
+
|
261
|
+
# The list of U.S. state codes and names used by the YouTube Analytics API.
|
262
|
+
# @see https://developers.google.com/youtube/analytics/v1/dimsmets/dims#province
|
263
|
+
US_STATES = {
|
264
|
+
AL: 'Alabama',
|
265
|
+
AK: 'Alaska',
|
266
|
+
AZ: 'Arizona',
|
267
|
+
AR: 'Arkansas',
|
268
|
+
CA: 'California',
|
269
|
+
CO: 'Colorado',
|
270
|
+
CT: 'Connecticut',
|
271
|
+
DE: 'Delaware',
|
272
|
+
FL: 'Florida',
|
273
|
+
GA: 'Georgia',
|
274
|
+
HI: 'Hawaii',
|
275
|
+
ID: 'Idaho',
|
276
|
+
IL: 'Illinois',
|
277
|
+
IN: 'Indiana',
|
278
|
+
IA: 'Iowa',
|
279
|
+
KS: 'Kansas',
|
280
|
+
KY: 'Kentucky',
|
281
|
+
LA: 'Louisiana',
|
282
|
+
ME: 'Maine',
|
283
|
+
MD: 'Maryland',
|
284
|
+
MA: 'Massachusetts',
|
285
|
+
MI: 'Michigan',
|
286
|
+
MN: 'Minnesota',
|
287
|
+
MS: 'Mississippi',
|
288
|
+
MO: 'Missouri',
|
289
|
+
MT: 'Montana',
|
290
|
+
NE: 'Nebraska',
|
291
|
+
NV: 'Nevada',
|
292
|
+
NH: 'New Hampshire',
|
293
|
+
NJ: 'New Jersey',
|
294
|
+
NM: 'New Mexico',
|
295
|
+
NY: 'New York',
|
296
|
+
NC: 'North Carolina',
|
297
|
+
ND: 'North Dakota',
|
298
|
+
OH: 'Ohio',
|
299
|
+
OK: 'Oklahoma',
|
300
|
+
OR: 'Oregon',
|
301
|
+
PA: 'Pennsylvania',
|
302
|
+
RI: 'Rhode Island',
|
303
|
+
SC: 'South Carolina',
|
304
|
+
SD: 'South Dakota',
|
305
|
+
TN: 'Tennessee',
|
306
|
+
TX: 'Texas',
|
307
|
+
UT: 'Utah',
|
308
|
+
VT: 'Vermont',
|
309
|
+
VA: 'Virginia',
|
310
|
+
WA: 'Washington',
|
311
|
+
WV: 'West Virginia',
|
312
|
+
WI: 'Wisconsin',
|
313
|
+
WY: 'Wyoming',
|
314
|
+
DC: 'District of Columbia',
|
315
|
+
AS: 'American Samoa',
|
316
|
+
GU: 'Guam',
|
317
|
+
MP: 'Northern Mariana Islands',
|
318
|
+
PR: 'Puerto Rico',
|
319
|
+
UM: 'United States Minor Outlying Islands',
|
320
|
+
VI: 'Virgin Islands, U.S.',
|
321
|
+
ZZ: 'Unknown Region'
|
322
|
+
}.with_indifferent_access
|
323
|
+
end
|
data/lib/yt/models/account.rb
CHANGED
@@ -160,6 +160,11 @@ module Yt
|
|
160
160
|
# upload videos using the resumable upload protocol.
|
161
161
|
has_many :resumable_sessions
|
162
162
|
|
163
|
+
# @!attribute [r] video_groups
|
164
|
+
# @return [Yt::Collections::VideoGroups] the video-groups created by the
|
165
|
+
# account.
|
166
|
+
has_many :video_groups
|
167
|
+
|
163
168
|
### PRIVATE API ###
|
164
169
|
|
165
170
|
has_authentication
|
@@ -180,6 +185,13 @@ module Yt
|
|
180
185
|
{for_mine: true}
|
181
186
|
end
|
182
187
|
|
188
|
+
# @private
|
189
|
+
# Tells `has_many :video_groups` that content_owner.groups should return
|
190
|
+
# all the video-groups *owned by* the account
|
191
|
+
def video_groups_params
|
192
|
+
{mine: true}
|
193
|
+
end
|
194
|
+
|
183
195
|
# @private
|
184
196
|
# Tells `has_many :resumable_sessions` what path to hit to upload a file.
|
185
197
|
def upload_path
|
@@ -30,6 +30,11 @@ module Yt
|
|
30
30
|
# @return [String] The display name of the content owner.
|
31
31
|
attr_reader :display_name
|
32
32
|
|
33
|
+
# @!attribute [r] video_groups
|
34
|
+
# @return [Yt::Collections::VideoGroups] the video-groups managed by the
|
35
|
+
# content owner.
|
36
|
+
has_many :video_groups
|
37
|
+
|
33
38
|
def initialize(options = {})
|
34
39
|
super options
|
35
40
|
@owner_name = options[:owner_name]
|
@@ -56,6 +61,13 @@ module Yt
|
|
56
61
|
def videos_params
|
57
62
|
{for_content_owner: true, on_behalf_of_content_owner: @owner_name}
|
58
63
|
end
|
64
|
+
|
65
|
+
# @private
|
66
|
+
# Tells `has_many :video_groups` that content_owner.video_groups should
|
67
|
+
# return all the video-groups *on behalf of* the content owner
|
68
|
+
def video_groups_params
|
69
|
+
{on_behalf_of_content_owner: @owner_name}
|
70
|
+
end
|
59
71
|
end
|
60
72
|
end
|
61
73
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Yt
|
2
|
+
module Models
|
3
|
+
class GroupInfo < Base
|
4
|
+
attr_reader :data
|
5
|
+
|
6
|
+
def initialize(options = {})
|
7
|
+
@data = options[:data]['snippet'].merge options[:data]['contentDetails']
|
8
|
+
@auth = options[:auth]
|
9
|
+
end
|
10
|
+
|
11
|
+
has_attribute :title, default: ''
|
12
|
+
has_attribute :item_count, type: Integer
|
13
|
+
has_attribute :published_at, type: Time
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'yt/models/base'
|
2
|
+
|
3
|
+
module Yt
|
4
|
+
module Models
|
5
|
+
# Provides methods to interact with YouTube Analytics video-groups.
|
6
|
+
# @see https://developers.google.com/youtube/analytics/v1/reference/groups
|
7
|
+
class VideoGroup < Base
|
8
|
+
# @private
|
9
|
+
attr_reader :id, :auth
|
10
|
+
|
11
|
+
### GROUP INFO ###
|
12
|
+
|
13
|
+
has_one :group_info
|
14
|
+
|
15
|
+
# @!attribute [r] title
|
16
|
+
# @return [String] the title of the group.
|
17
|
+
delegate :title, to: :group_info
|
18
|
+
|
19
|
+
# @!attribute [r] item_count
|
20
|
+
# @return [Integer] the number of resources in the group.
|
21
|
+
delegate :item_count, to: :group_info
|
22
|
+
|
23
|
+
# @!attribute [r] published_at
|
24
|
+
# @return [Time] the date and time when the group was created.
|
25
|
+
delegate :published_at, to: :group_info
|
26
|
+
|
27
|
+
### ANALYTICS ###
|
28
|
+
|
29
|
+
# @macro reports
|
30
|
+
|
31
|
+
# @macro report_by_video_dimensions
|
32
|
+
has_report :views, Integer
|
33
|
+
|
34
|
+
# @macro report_by_day
|
35
|
+
has_report :uniques, Integer
|
36
|
+
|
37
|
+
# @macro report_by_video_dimensions
|
38
|
+
has_report :estimated_minutes_watched, Integer
|
39
|
+
|
40
|
+
# @macro report_by_gender_and_age_group
|
41
|
+
has_report :viewer_percentage, Float
|
42
|
+
|
43
|
+
# @macro report_by_day_and_country
|
44
|
+
has_report :comments, Integer
|
45
|
+
|
46
|
+
# @macro report_by_day_and_country
|
47
|
+
has_report :likes, Integer
|
48
|
+
|
49
|
+
# @macro report_by_day_and_country
|
50
|
+
has_report :dislikes, Integer
|
51
|
+
|
52
|
+
# @macro report_by_day_and_country
|
53
|
+
has_report :shares, Integer
|
54
|
+
|
55
|
+
# @note This is not the total number of subscribers gained by the video’s
|
56
|
+
# channel, but the subscribers gained *from* the video’s page.
|
57
|
+
# @macro report_by_day_and_country
|
58
|
+
has_report :subscribers_gained, Integer
|
59
|
+
|
60
|
+
# @note This is not the total number of subscribers lost by the video’s
|
61
|
+
# channel, but the subscribers lost *from* the video’s page.
|
62
|
+
# @macro report_by_day_and_country
|
63
|
+
has_report :subscribers_lost, Integer
|
64
|
+
|
65
|
+
# @macro report_by_day_and_country
|
66
|
+
has_report :favorites_added, Integer
|
67
|
+
|
68
|
+
# @macro report_by_day_and_country
|
69
|
+
has_report :favorites_removed, Integer
|
70
|
+
|
71
|
+
# @macro report_by_day_and_country
|
72
|
+
has_report :videos_added_to_playlists, Integer
|
73
|
+
|
74
|
+
# @macro report_by_day_and_country
|
75
|
+
has_report :videos_removed_from_playlists, Integer
|
76
|
+
|
77
|
+
# @macro report_by_day_and_state
|
78
|
+
has_report :average_view_duration, Integer
|
79
|
+
|
80
|
+
# @macro report_by_day_and_state
|
81
|
+
has_report :average_view_percentage, Float
|
82
|
+
|
83
|
+
# @macro report_by_day_and_state
|
84
|
+
has_report :annotation_clicks, Integer
|
85
|
+
|
86
|
+
# @macro report_by_day_and_state
|
87
|
+
has_report :annotation_click_through_rate, Float
|
88
|
+
|
89
|
+
# @macro report_by_day_and_state
|
90
|
+
has_report :annotation_close_rate, Float
|
91
|
+
|
92
|
+
# @macro report_by_day_and_country
|
93
|
+
has_report :earnings, Float
|
94
|
+
|
95
|
+
# @macro report_by_day_and_country
|
96
|
+
has_report :impressions, Integer
|
97
|
+
|
98
|
+
# @macro report_by_day_and_country
|
99
|
+
has_report :monetized_playbacks, Integer
|
100
|
+
|
101
|
+
# @macro report_by_day_and_country
|
102
|
+
has_report :playback_based_cpm, Float
|
103
|
+
|
104
|
+
### PRIVATE API ###
|
105
|
+
|
106
|
+
# @private
|
107
|
+
def initialize(options = {})
|
108
|
+
@id = options[:id]
|
109
|
+
@auth = options[:auth]
|
110
|
+
@group_info = options[:group_info] if options[:group_info]
|
111
|
+
end
|
112
|
+
|
113
|
+
# @private
|
114
|
+
# Tells `has_reports` to retrieve group reports from the Analytics API.
|
115
|
+
def reports_params
|
116
|
+
{}.tap do |params|
|
117
|
+
if auth.owner_name
|
118
|
+
params[:ids] = "contentOwner==#{auth.owner_name}"
|
119
|
+
else
|
120
|
+
params[:ids] = "channel==mine"
|
121
|
+
end
|
122
|
+
params[:filters] = "group==#{id}"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
data/lib/yt/request.rb
CHANGED
@@ -210,6 +210,7 @@ module Yt
|
|
210
210
|
Errno::ENETUNREACH,
|
211
211
|
Errno::ECONNRESET,
|
212
212
|
Net::OpenTimeout,
|
213
|
+
SocketError,
|
213
214
|
Net::HTTPServerError
|
214
215
|
] + extra_server_errors
|
215
216
|
end
|
@@ -233,7 +234,7 @@ module Yt
|
|
233
234
|
@retries_so_far += 1
|
234
235
|
if (@retries_so_far < max_retries)
|
235
236
|
@response = @http_request = @uri = nil
|
236
|
-
sleep 3
|
237
|
+
sleep 3 + (10 * @retries_so_far)
|
237
238
|
end
|
238
239
|
end
|
239
240
|
|
data/lib/yt/version.rb
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'yt/constants/geography'
|
3
|
+
|
4
|
+
describe 'Yt::COUNTRIES' do
|
5
|
+
it 'returns all country codes and names' do
|
6
|
+
expect(Yt::COUNTRIES[:US]).to eq 'United States'
|
7
|
+
expect(Yt::COUNTRIES['IT']).to eq 'Italy'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'Yt::US_STATES' do
|
12
|
+
it 'returns all U.S. state codes and names' do
|
13
|
+
expect(Yt::US_STATES[:CA]).to eq 'California'
|
14
|
+
expect(Yt::US_STATES['CO']).to eq 'Colorado'
|
15
|
+
end
|
16
|
+
end
|
data/spec/models/request_spec.rb
CHANGED
@@ -178,6 +178,27 @@ describe Yt::Request do
|
|
178
178
|
it { expect{request.run}.not_to fail }
|
179
179
|
end
|
180
180
|
end
|
181
|
+
|
182
|
+
# NOTE: This test is just a reflection of YouTube irrational behavior of
|
183
|
+
# being unavailable once in a while, and therefore causing Net::HTTP to
|
184
|
+
# fail, although retrying after some seconds works.
|
185
|
+
context 'a SocketError', ruby21: true do
|
186
|
+
let(:http_error) { SocketError.new }
|
187
|
+
|
188
|
+
context 'every time' do
|
189
|
+
before { expect(Net::HTTP).to receive(:start).at_least(:once).and_raise http_error }
|
190
|
+
|
191
|
+
it { expect{request.run}.to fail }
|
192
|
+
end
|
193
|
+
|
194
|
+
context 'but works the second time' do
|
195
|
+
before { expect(Net::HTTP).to receive(:start).at_least(:once).and_return retry_response }
|
196
|
+
before { allow(retry_response).to receive(:body) }
|
197
|
+
let(:retry_response) { Net::HTTPOK.new nil, nil, nil }
|
198
|
+
|
199
|
+
it { expect{request.run}.not_to fail }
|
200
|
+
end
|
201
|
+
end
|
181
202
|
end
|
182
203
|
end
|
183
204
|
end
|
@@ -97,6 +97,21 @@ describe Yt::Account, :device_app do
|
|
97
97
|
end
|
98
98
|
end
|
99
99
|
|
100
|
+
describe '.video_groups' do
|
101
|
+
let(:video_group) { $account.video_groups.first }
|
102
|
+
|
103
|
+
specify 'returns the first video-group created by the account' do
|
104
|
+
expect(video_group).to be_a Yt::VideoGroup
|
105
|
+
expect(video_group.title).to be_a String
|
106
|
+
expect(video_group.item_count).to be_an Integer
|
107
|
+
expect(video_group.published_at).to be_a Time
|
108
|
+
end
|
109
|
+
|
110
|
+
specify 'allows to run reports against each video-group' do
|
111
|
+
expect(video_group.views).to be
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
100
115
|
describe '.upload_video' do
|
101
116
|
let(:video_params) { {title: 'Test Yt upload', privacy_status: 'private', category_id: 17} }
|
102
117
|
let(:video) { $account.upload_video path_or_url, video_params }
|
@@ -51,6 +51,20 @@ describe Yt::ContentOwner, :partner do
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
+
describe '.video_groups' do
|
55
|
+
let(:video_group) { $content_owner.video_groups.first }
|
56
|
+
|
57
|
+
specify 'returns the first video-group created by the account' do
|
58
|
+
expect(video_group).to be_a Yt::VideoGroup
|
59
|
+
expect(video_group.title).to be_a String
|
60
|
+
expect(video_group.item_count).to be_an Integer
|
61
|
+
expect(video_group.published_at).to be_a Time
|
62
|
+
end
|
63
|
+
|
64
|
+
specify 'allows to run reports against each video-group' do
|
65
|
+
expect(video_group.views).to be
|
66
|
+
end
|
67
|
+
end
|
54
68
|
|
55
69
|
describe 'claims' do
|
56
70
|
let(:asset_id) { ENV['YT_TEST_PARTNER_ASSET_ID'] }
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'yt/models/video_group'
|
3
|
+
|
4
|
+
describe Yt::VideoGroup, :partner do
|
5
|
+
subject(:video_group) { Yt::VideoGroup.new id: id, auth: $content_owner }
|
6
|
+
|
7
|
+
context 'given a video-group', :partner do
|
8
|
+
context 'managed by the authenticated Content Owner' do
|
9
|
+
let(:id) { ENV['YT_TEST_PARTNER_VIDEO_GROUP_ID'] }
|
10
|
+
|
11
|
+
specify 'the title can be retrieved' do
|
12
|
+
expect(video_group.title).to be_a(String)
|
13
|
+
expect(video_group.title).not_to be_empty
|
14
|
+
end
|
15
|
+
|
16
|
+
specify 'the number of videos in the group can be retrieved' do
|
17
|
+
expect(video_group.item_count).to be_an(Integer)
|
18
|
+
expect(video_group.item_count).not_to be_zero
|
19
|
+
end
|
20
|
+
|
21
|
+
describe 'multiple reports can be retrieved at once' do
|
22
|
+
metrics = {views: Integer, uniques: Integer,
|
23
|
+
estimated_minutes_watched: Integer, comments: Integer, likes: Integer,
|
24
|
+
dislikes: Integer, shares: Integer, subscribers_gained: Integer,
|
25
|
+
subscribers_lost: Integer, favorites_added: Integer,
|
26
|
+
videos_added_to_playlists: Integer, videos_removed_from_playlists: Integer,
|
27
|
+
favorites_removed: Integer, average_view_duration: Integer,
|
28
|
+
average_view_percentage: Float, annotation_clicks: Integer,
|
29
|
+
annotation_click_through_rate: Float,
|
30
|
+
annotation_close_rate: Float, earnings: Float, impressions: Integer,
|
31
|
+
monetized_playbacks: Integer}
|
32
|
+
|
33
|
+
specify 'by day, and are chronologically sorted' do
|
34
|
+
range = {since: 5.days.ago.to_date, until: 3.days.ago.to_date}
|
35
|
+
result = video_group.reports range.merge(only: metrics, by: :day)
|
36
|
+
metrics.each do |metric, type|
|
37
|
+
expect(result[metric].keys).to all(be_a Date)
|
38
|
+
expect(result[metric].values).to all(be_a type)
|
39
|
+
expect(result[metric].keys.sort).to eq result[metric].keys
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# NOTE: all the other filters also apply, not tested for brevity
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'viewer_percentage can be grouped by age group' do
|
47
|
+
let(:range) { {since: 1.year.ago.to_date, until: 1.week.ago.to_date} }
|
48
|
+
let(:keys) { range.values }
|
49
|
+
|
50
|
+
specify 'with the :by option set to :age_group' do
|
51
|
+
viewer_percentage = video_group.viewer_percentage range.merge by: :age_group
|
52
|
+
expect(viewer_percentage.keys - %w(65- 35-44 45-54 13-17 25-34 55-64 18-24)).to be_empty
|
53
|
+
expect(viewer_percentage.values).to all(be_instance_of Float)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'not managed by the authenticated Content Owner' do
|
59
|
+
let(:id) { 'ABExJp9gAAA' }
|
60
|
+
|
61
|
+
specify 'views cannot be retrieved' do
|
62
|
+
expect{video_group.views}.to raise_error Yt::Error
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/spec/spec_helper.rb
CHANGED
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.25.
|
4
|
+
version: 0.25.18
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Claudio Baccigalupo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-01-
|
11
|
+
date: 2016-01-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -142,6 +142,7 @@ files:
|
|
142
142
|
- lib/yt/collections/content_owners.rb
|
143
143
|
- lib/yt/collections/device_flows.rb
|
144
144
|
- lib/yt/collections/file_details.rb
|
145
|
+
- lib/yt/collections/group_infos.rb
|
145
146
|
- lib/yt/collections/ids.rb
|
146
147
|
- lib/yt/collections/live_streaming_details.rb
|
147
148
|
- lib/yt/collections/ownerships.rb
|
@@ -165,8 +166,10 @@ files:
|
|
165
166
|
- lib/yt/collections/subscriptions.rb
|
166
167
|
- lib/yt/collections/user_infos.rb
|
167
168
|
- lib/yt/collections/video_categories.rb
|
169
|
+
- lib/yt/collections/video_groups.rb
|
168
170
|
- lib/yt/collections/videos.rb
|
169
171
|
- lib/yt/config.rb
|
172
|
+
- lib/yt/constants/geography.rb
|
170
173
|
- lib/yt/errors/forbidden.rb
|
171
174
|
- lib/yt/errors/missing_auth.rb
|
172
175
|
- lib/yt/errors/no_items.rb
|
@@ -192,6 +195,7 @@ files:
|
|
192
195
|
- lib/yt/models/description.rb
|
193
196
|
- lib/yt/models/device_flow.rb
|
194
197
|
- lib/yt/models/file_detail.rb
|
198
|
+
- lib/yt/models/group_info.rb
|
195
199
|
- lib/yt/models/id.rb
|
196
200
|
- lib/yt/models/iterator.rb
|
197
201
|
- lib/yt/models/live_streaming_detail.rb
|
@@ -217,6 +221,7 @@ files:
|
|
217
221
|
- lib/yt/models/user_info.rb
|
218
222
|
- lib/yt/models/video.rb
|
219
223
|
- lib/yt/models/video_category.rb
|
224
|
+
- lib/yt/models/video_group.rb
|
220
225
|
- lib/yt/request.rb
|
221
226
|
- lib/yt/version.rb
|
222
227
|
- spec/collections/claims_spec.rb
|
@@ -227,6 +232,7 @@ files:
|
|
227
232
|
- spec/collections/reports_spec.rb
|
228
233
|
- spec/collections/subscriptions_spec.rb
|
229
234
|
- spec/collections/videos_spec.rb
|
235
|
+
- spec/constants/geography_spec.rb
|
230
236
|
- spec/errors/forbidden_spec.rb
|
231
237
|
- spec/errors/missing_auth_spec.rb
|
232
238
|
- spec/errors/no_items_spec.rb
|
@@ -283,6 +289,7 @@ files:
|
|
283
289
|
- spec/requests/as_content_owner/match_policy_spec.rb
|
284
290
|
- spec/requests/as_content_owner/ownership_spec.rb
|
285
291
|
- spec/requests/as_content_owner/playlist_spec.rb
|
292
|
+
- spec/requests/as_content_owner/video_group_spec.rb
|
286
293
|
- spec/requests/as_content_owner/video_spec.rb
|
287
294
|
- spec/requests/as_server_app/channel_spec.rb
|
288
295
|
- spec/requests/as_server_app/playlist_item_spec.rb
|
@@ -328,6 +335,7 @@ test_files:
|
|
328
335
|
- spec/collections/reports_spec.rb
|
329
336
|
- spec/collections/subscriptions_spec.rb
|
330
337
|
- spec/collections/videos_spec.rb
|
338
|
+
- spec/constants/geography_spec.rb
|
331
339
|
- spec/errors/forbidden_spec.rb
|
332
340
|
- spec/errors/missing_auth_spec.rb
|
333
341
|
- spec/errors/no_items_spec.rb
|
@@ -384,6 +392,7 @@ test_files:
|
|
384
392
|
- spec/requests/as_content_owner/match_policy_spec.rb
|
385
393
|
- spec/requests/as_content_owner/ownership_spec.rb
|
386
394
|
- spec/requests/as_content_owner/playlist_spec.rb
|
395
|
+
- spec/requests/as_content_owner/video_group_spec.rb
|
387
396
|
- spec/requests/as_content_owner/video_spec.rb
|
388
397
|
- spec/requests/as_server_app/channel_spec.rb
|
389
398
|
- spec/requests/as_server_app/playlist_item_spec.rb
|