yt 0.25.17 → 0.25.18
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/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
|