brainzz 0.0.2 → 0.0.3

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: 5593938f8cecb4660e3c474a61dcbf908a74f0a2
4
- data.tar.gz: 2db3a9a659c9241a7501870fb212a57f73accfa7
3
+ metadata.gz: 8b0778b1b4125407b03db2409943f825a0175ed0
4
+ data.tar.gz: a380360a2548603619f847f20cad660367ba70e7
5
5
  SHA512:
6
- metadata.gz: 2387071a7d82e12d58798ccade04c873531aa77335fc1931c4a61f2ec688c3e30b290567ed02805e0f40ad323adeea368edc64e4eda774a3daa81d6bb7df8111
7
- data.tar.gz: 5821bb60c0a98d8c8f04319450d4ac282c609800352781518d776cf4415bc6525facb147d2a6014cc57807dad56b792ea4b2992e4af84cf19dc7706f109544d1
6
+ metadata.gz: 65e2ecf248cbaf6c936f4e26f3fc71a6e6948776dbf4abcfa747489c46a530a776b0f570ab64fe520f4b89edf122159aee295460f3db14e1786f2a612aac8af6
7
+ data.tar.gz: be9d7f05e156220dfa77132b0c688c0daecef19fda6f4abf2298db63f14bed1023ee5fa89f76b34439a23b2a42c00a8c5e1a8ab78182291f56dc60fe01e18b4a
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  Brainzz
2
2
  =======
3
3
 
4
+ [![Build Status](https://semaphoreci.com/api/v1/projects/6bcf66fa-7d8c-4027-93ae-13b6bb75325f/346455/badge.png)](https://semaphoreci.com/awesomenesstv/brainzz)
5
+
4
6
  Brainzz explains why youtoobers' brainzz are turned to mush.
5
7
  ... by extracting data from the YouTube API.
6
8
 
@@ -19,24 +21,22 @@ Run Specs
19
21
 
20
22
  ### Regenerating VCR Cassettes
21
23
 
22
- In order to regenerate vcr cassettes,
23
- the google api key is needed.
24
-
25
- Follow the instructions [here][atv-wiki-google-api-key] to retrieve it.
24
+ Check `config/dotenv/test.env` for the required keys.
26
25
 
27
- Place this value in a file named `.env` in the root of the project
26
+ Follow the instructions [here][atv-wiki-google-api-key]
27
+ to find the required values.
28
28
 
29
- The `.env` contents should look something like this:
29
+ `REFRESH_TOKEN` is only required for testing purposes.
30
+ Consumers will not need to set this value,
31
+ as it will be passed in via parameters to methods that require it.
30
32
 
31
- ```
32
- GOOGLE_API_KEY = [API KEY]
33
- ```
33
+ Place them in `config/dotenv/integration.env`.
34
34
 
35
35
 
36
36
  Usage
37
37
  -----
38
38
 
39
- A `GOOGLE_API_KEY` environment variable is expected to be set
39
+ A `BRAINZZ_GOOGLE_API_KEY` environment variable is expected to be set
40
40
  by any application that consumes this gem.
41
41
 
42
42
 
@@ -72,4 +72,70 @@ while response.nil? || !response.data.last_page?
72
72
  end
73
73
  ```
74
74
 
75
+
76
+ ### video_details_for
77
+
78
+ Accepts an array of video ids.
79
+ The maximum length of the array is determined by YouTube.
80
+ It is currently limited to 50 videos.
81
+
82
+ This endpoint returns a hash with video ids as keys
83
+ and video objects as the values.
84
+
85
+
86
+ ### views_for
87
+
88
+ #### Parameters
89
+
90
+ * channel id (String)
91
+ * video id (String)
92
+ * start date (DateTime)
93
+ * end date (DateTime)
94
+ * refresh token (String)
95
+
96
+ Refresh token must be a refresh token for the channel owner
97
+ using the same client id and client secret that are set in
98
+ `BRAINZZ_CLIENT_ID` and `BRAINZZ_CLIENT_SECRET`.
99
+
100
+
101
+ #### Result
102
+
103
+ An array of `Brainzz::ViewCount` objects ordered by date in ascending order.
104
+
105
+ `#source` will be an integer (or nil) value
106
+ corresponding to the following YouTube referrals:
107
+
108
+ ADVERTISING = 1
109
+ ANNOTATION = 2
110
+ EXT_URL = 3
111
+ NO_LINK_EMBEDDED = 4
112
+ NO_LINK_OTHER = 5
113
+ PLAYLIST = 6
114
+ PROMOTED = 7
115
+ RELATED_VIDEO = 8
116
+ SUBSCRIBER = 9
117
+ YT_CHANNEL = 10
118
+ YT_OTHER_PAGE = 11
119
+ YT_SEARCH = 12
120
+
121
+ The constants are defined in `Brainzz::ViewCountEnum`
122
+
123
+
124
+ Factories
125
+ ---------
126
+
127
+ Brainzz includes FactoryGirl factories for your convenience.
128
+ Include them after requiring FactoryGirl:
129
+
130
+ require 'brainzz/factories'
131
+
132
+
133
+ Deployment
134
+ ----------
135
+
136
+ This project makes use of branches to manage deployment.
137
+ Pushing a new commit to the `production` branch
138
+ will also build and push this gem to RubyGems.
139
+
140
+
75
141
  [atv-wiki-google-api-key]: https://www.github.com/awesomenesstv/wiki#google-api-key
data/lib/brainzz.rb CHANGED
@@ -4,23 +4,36 @@ require 'date'
4
4
  require 'faraday'
5
5
 
6
6
  require 'reverb'
7
+ require 'toke'
7
8
 
8
- module Brainzz
9
- end
10
-
11
- require_relative 'brainzz/core'
9
+ require_relative 'brainzz/enums/view_source_enum'
12
10
 
13
11
  require_relative 'brainzz/models/base_model'
14
12
  require_relative 'brainzz/models/video'
13
+ require_relative 'brainzz/models/view_count'
15
14
  require_relative 'brainzz/models/playlist_item'
16
15
  require_relative 'brainzz/models/playlist_items_wrapper'
17
16
 
17
+ require_relative 'brainzz/services/access_token_service'
18
+
19
+ require_relative 'brainzz/params/base_params'
20
+ require_relative 'brainzz/params/analytics_params'
21
+ require_relative 'brainzz/params/video_details_params'
22
+ require_relative 'brainzz/params/view_count_params'
23
+ require_relative 'brainzz/params/playlist_items_params'
24
+
18
25
  require_relative 'brainzz/responses/playlist_items_response'
19
26
  require_relative 'brainzz/responses/video_details_response'
27
+ require_relative 'brainzz/responses/view_count_response'
20
28
 
21
29
  require_relative 'brainzz/commands/base_command'
30
+ require_relative 'brainzz/commands/data_command'
31
+ require_relative 'brainzz/commands/analytics_command'
22
32
  require_relative 'brainzz/commands/playlist_items_command'
23
33
  require_relative 'brainzz/commands/video_details_command'
34
+ require_relative 'brainzz/commands/view_count_command'
35
+
36
+ require_relative 'brainzz/core'
24
37
 
25
38
  module Brainzz
26
39
  extend Core
@@ -0,0 +1,21 @@
1
+ module Brainzz
2
+ class AnalyticsCommand < BaseCommand
3
+ class << self
4
+ private
5
+
6
+ def headers(parameters)
7
+ super.merge({
8
+ 'Authorization' => "Bearer #{access_token(parameters)}",
9
+ })
10
+ end
11
+
12
+ def base_url
13
+ 'https://www.googleapis.com/youtube/analytics/v1'
14
+ end
15
+
16
+ def access_token(parameters)
17
+ AccessTokenService.retrieve_token parameters.refresh_token
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,29 +1,29 @@
1
1
  module Brainzz
2
- module BaseCommand
3
- extend self
2
+ class BaseCommand
3
+ class << self
4
+ private
4
5
 
5
- private
6
+ def get(parameters)
7
+ connection.get endpoint, params(parameters), headers(parameters)
8
+ end
6
9
 
7
- def connection
8
- Faraday.new(:url => base_url)
9
- end
10
+ def connection
11
+ Faraday.new(:url => base_url)
12
+ end
10
13
 
11
- def params
12
- url_params.merge({
13
- :key => api_key,
14
- })
15
- end
14
+ def params(parameters = nil)
15
+ {}
16
+ end
16
17
 
17
- def url_params
18
- {}
19
- end
20
-
21
- def api_key
22
- ENV['GOOGLE_API_KEY']
23
- end
18
+ def headers(parameters = nil)
19
+ {
20
+ 'Content-Type' => 'application/json',
21
+ }
22
+ end
24
23
 
25
- def base_url
26
- 'https://www.googleapis.com/youtube/v3'
24
+ def url(parameters)
25
+ connection.build_url endpoint, params(parameters)
26
+ end
27
27
  end
28
28
  end
29
29
  end
@@ -0,0 +1,19 @@
1
+ module Brainzz
2
+ class DataCommand < BaseCommand
3
+ class << self
4
+ def params(parameters = nil)
5
+ super.merge({
6
+ :key => api_key,
7
+ })
8
+ end
9
+
10
+ def base_url
11
+ 'https://www.googleapis.com/youtube/v3'
12
+ end
13
+
14
+ def api_key
15
+ ENV['BRAINZZ_GOOGLE_API_KEY']
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,28 +1,37 @@
1
1
  module Brainzz
2
- module PlaylistItemsCommand
3
- extend BaseCommand
4
- extend self
2
+ class PlaylistItemsCommand < DataCommand
3
+ class << self
4
+ def execute(playlist_id, response)
5
+ playlist_items_params = PlaylistItemsParams.new(playlist_id, response)
5
6
 
6
- def execute(playlist_id, response)
7
- @response = response
8
- @playlist_id = playlist_id
9
- response = connection.get('playlistItems', params)
10
- PlaylistItemsResponse.new response
11
- end
7
+ if playlist_items_params.valid?
8
+ response = get(playlist_items_params)
9
+ PlaylistItemsResponse.new response
10
+ else
11
+ PlaylistItemsResponse.new
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def endpoint
18
+ 'playlistItems'
19
+ end
12
20
 
13
- private
21
+ def params(playlist_items_params)
22
+ args = {
23
+ 'playlistId' => playlist_items_params.playlist_id,
24
+ 'part' => 'contentDetails',
25
+ 'maxResults' => 50,
26
+ }
14
27
 
15
- def url_params
16
- params = {
17
- 'playlistId' => @playlist_id,
18
- 'part' => 'contentDetails',
19
- 'maxResults' => 50,
20
- }
28
+ if playlist_items_params.next_page_token
29
+ args.merge!({
30
+ 'pageToken' => playlist_items_params.next_page_token
31
+ })
32
+ end
21
33
 
22
- if @response
23
- params.merge({'pageToken' => @response.data.next_page_token})
24
- else
25
- params
34
+ super.merge args
26
35
  end
27
36
  end
28
37
  end
@@ -1,21 +1,29 @@
1
1
  module Brainzz
2
- module VideoDetailsCommand
3
- extend BaseCommand
4
- extend self
2
+ class VideoDetailsCommand < DataCommand
3
+ class << self
4
+ def execute(video_ids)
5
+ video_details_params = VideoDetailsParams.new(video_ids)
5
6
 
6
- def execute(video_ids)
7
- @video_ids = video_ids
8
- response = connection.get('videos', params)
9
- VideoDetailsResponse.new response
10
- end
7
+ if video_details_params.valid?
8
+ response = get(video_details_params)
9
+ VideoDetailsResponse.new response
10
+ else
11
+ VideoDetailsResponse.new
12
+ end
13
+ end
14
+
15
+ private
11
16
 
12
- private
17
+ def endpoint
18
+ 'videos'
19
+ end
13
20
 
14
- def url_params
15
- {
16
- 'id' => @video_ids.join(','),
17
- 'part' => 'snippet',
18
- }
21
+ def params(video_details_params)
22
+ super.merge({
23
+ 'id' => video_details_params.video_ids.join(','),
24
+ 'part' => 'snippet',
25
+ })
26
+ end
19
27
  end
20
28
  end
21
29
  end
@@ -0,0 +1,39 @@
1
+ module Brainzz
2
+ class ViewCountCommand < AnalyticsCommand
3
+ class << self
4
+ def execute(channel_id, video_id, start_date, end_date, refresh_token)
5
+ view_count_params = ViewCountParams.new({
6
+ :channel_id => channel_id,
7
+ :video_id => video_id,
8
+ :start_date => start_date,
9
+ :end_date => end_date,
10
+ :refresh_token => refresh_token
11
+ })
12
+
13
+ if view_count_params.valid?
14
+ ViewCountResponse.new get(view_count_params)
15
+ else
16
+ ViewCountResponse.new
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def endpoint
23
+ 'reports'
24
+ end
25
+
26
+ def params(view_count_params)
27
+ super.merge({
28
+ 'ids' => "channel==#{view_count_params.channel_id}",
29
+ 'filter' => "video==#{view_count_params.video_id}",
30
+ 'metrics' => 'views',
31
+ 'dimensions' => 'day,insightTrafficSourceType',
32
+ 'start-date' => view_count_params.start_date,
33
+ 'end-date' => view_count_params.end_date,
34
+ 'sort' => 'day',
35
+ })
36
+ end
37
+ end
38
+ end
39
+ end
data/lib/brainzz/core.rb CHANGED
@@ -7,7 +7,12 @@ module Brainzz
7
7
  end
8
8
 
9
9
  def video_details_for(video_ids)
10
- VideoDetailsCommand.execute(video_ids)
10
+ VideoDetailsCommand.execute video_ids
11
+ end
12
+
13
+ def views_for(channel_id, video_id, start_date, end_date, refresh_token)
14
+ ViewCountCommand.execute(
15
+ channel_id, video_id, start_date, end_date, refresh_token)
11
16
  end
12
17
  end
13
18
  end
@@ -0,0 +1,31 @@
1
+ module Brainzz
2
+ module ViewSourceEnum
3
+ ADVERTISING = 1
4
+ ANNOTATION = 2
5
+ EXT_URL = 3
6
+ NO_LINK_EMBEDDED = 4
7
+ NO_LINK_OTHER = 5
8
+ PLAYLIST = 6
9
+ PROMOTED = 7
10
+ RELATED_VIDEO = 8
11
+ SUBSCRIBER = 9
12
+ YT_CHANNEL = 10
13
+ YT_OTHER_PAGE = 11
14
+ YT_SEARCH = 12
15
+
16
+ SOURCES = {
17
+ 'advertising' => ADVERTISING,
18
+ 'annotation' => ANNOTATION,
19
+ 'ext_url' => EXT_URL,
20
+ 'no_link_embedded' => NO_LINK_EMBEDDED,
21
+ 'no_link_other' => NO_LINK_OTHER,
22
+ 'playlist' => PLAYLIST,
23
+ 'promoted' => PROMOTED,
24
+ 'related_video' => RELATED_VIDEO,
25
+ 'subscriber' => SUBSCRIBER,
26
+ 'yt_channel' => YT_CHANNEL,
27
+ 'yt_other_page' => YT_OTHER_PAGE,
28
+ 'yt_search' => YT_SEARCH,
29
+ }
30
+ end
31
+ end
@@ -19,7 +19,7 @@ module Brainzz
19
19
  def transform_date(value)
20
20
  value = transform(value)
21
21
  return nil unless value.is_a?(String)
22
- DateTime.parse(value)
22
+ DateTime.parse value
23
23
  end
24
24
  end
25
25
  end
@@ -0,0 +1,22 @@
1
+ module Brainzz
2
+ class ViewCount < BaseModel
3
+ attr_reader :views, :day, :source
4
+
5
+ def initialize(view_count_row)
6
+ @views = normalize_views(view_count_row[2])
7
+ @day = transform_date(view_count_row[0])
8
+ @source = source_value(view_count_row[1])
9
+ end
10
+
11
+ private
12
+
13
+ def normalize_views(views)
14
+ return views ? views.to_i : 0
15
+ end
16
+
17
+ def source_value(source)
18
+ source = '' unless source.is_a?(String)
19
+ Brainzz::ViewSourceEnum::SOURCES[source.downcase]
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,19 @@
1
+ module Brainzz
2
+ class AnalyticsParams < BaseParams
3
+ attr_reader :channel_id
4
+ attr_reader :start_date
5
+ attr_reader :end_date
6
+ attr_reader :refresh_token
7
+
8
+ def initialize(params)
9
+ @channel_id = normalize(params[:channel_id])
10
+ @start_date = normalize_date(params[:start_date])
11
+ @end_date = normalize_date(params[:end_date])
12
+ @refresh_token = normalize(params[:refresh_token])
13
+ end
14
+
15
+ def valid?
16
+ !!(channel_id && start_date && end_date && refresh_token)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,14 @@
1
+ module Brainzz
2
+ class BaseParams
3
+ private
4
+
5
+ def normalize(value)
6
+ value = nil if value && value.strip == ''
7
+ value
8
+ end
9
+
10
+ def normalize_date(date)
11
+ date.strftime('%F') if date.respond_to?(:strftime)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,20 @@
1
+ module Brainzz
2
+ class PlaylistItemsParams < BaseParams
3
+ attr_reader :playlist_id, :next_page_token
4
+
5
+ def initialize(playlist_id, response)
6
+ @playlist_id = normalize(playlist_id)
7
+ @next_page_token = page_token_for(response)
8
+ end
9
+
10
+ def valid?
11
+ !!playlist_id
12
+ end
13
+
14
+ private
15
+
16
+ def page_token_for(response)
17
+ response && response.data && response.data.next_page_token
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,13 @@
1
+ module Brainzz
2
+ class VideoDetailsParams
3
+ attr_reader :video_ids
4
+
5
+ def initialize(video_ids)
6
+ @video_ids = video_ids
7
+ end
8
+
9
+ def valid?
10
+ !!(@video_ids && !@video_ids.empty?)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ module Brainzz
2
+ class ViewCountParams < AnalyticsParams
3
+ attr_reader :video_id
4
+
5
+ def initialize(params)
6
+ super
7
+ @video_id = normalize(params[:video_id])
8
+ end
9
+
10
+ def valid?
11
+ !!(super && video_id)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ module Brainzz
2
+ class ViewCountResponse < Reverb::Response
3
+ def on_success
4
+ self.data = []
5
+ body['rows'].each do |row|
6
+ self.data << ViewCount.new(row)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,28 @@
1
+ module Brainzz
2
+ module AccessTokenService
3
+ extend self
4
+
5
+ @@mutex = Mutex.new
6
+
7
+ def retrieve_token(refresh_token)
8
+ @@mutex.synchronize do
9
+ if !defined?(@token) or @token.expired?
10
+ response = Toke.retrieve_token(params(refresh_token))
11
+ @token = response.data if response.success?
12
+ end
13
+
14
+ @token.token if defined?(@token)
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def params(refresh_token)
21
+ {
22
+ :refresh_token => refresh_token,
23
+ :client_id => ENV['BRAINZZ_CLIENT_ID'],
24
+ :client_secret => ENV['BRAINZZ_CLIENT_SECRET'],
25
+ }
26
+ end
27
+ end
28
+ end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brainzz
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Travis Herrick
8
- - Meagan Cooney
8
+ - Joshua Book
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-02-24 00:00:00.000000000 Z
12
+ date: 2015-03-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: faraday
@@ -39,6 +39,20 @@ dependencies:
39
39
  - - "~>"
40
40
  - !ruby/object:Gem::Version
41
41
  version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: toke
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
42
56
  - !ruby/object:Gem::Dependency
43
57
  name: gems
44
58
  requirement: !ruby/object:Gem::Requirement
@@ -163,10 +177,14 @@ extra_rdoc_files:
163
177
  files:
164
178
  - README.md
165
179
  - lib/brainzz.rb
180
+ - lib/brainzz/commands/analytics_command.rb
166
181
  - lib/brainzz/commands/base_command.rb
182
+ - lib/brainzz/commands/data_command.rb
167
183
  - lib/brainzz/commands/playlist_items_command.rb
168
184
  - lib/brainzz/commands/video_details_command.rb
185
+ - lib/brainzz/commands/view_count_command.rb
169
186
  - lib/brainzz/core.rb
187
+ - lib/brainzz/enums/view_source_enum.rb
170
188
  - lib/brainzz/factories.rb
171
189
  - lib/brainzz/factories/playlist_item.rb
172
190
  - lib/brainzz/factories/playlist_items_wrapper.rb
@@ -176,8 +194,16 @@ files:
176
194
  - lib/brainzz/models/playlist_item.rb
177
195
  - lib/brainzz/models/playlist_items_wrapper.rb
178
196
  - lib/brainzz/models/video.rb
197
+ - lib/brainzz/models/view_count.rb
198
+ - lib/brainzz/params/analytics_params.rb
199
+ - lib/brainzz/params/base_params.rb
200
+ - lib/brainzz/params/playlist_items_params.rb
201
+ - lib/brainzz/params/video_details_params.rb
202
+ - lib/brainzz/params/view_count_params.rb
179
203
  - lib/brainzz/responses/playlist_items_response.rb
180
204
  - lib/brainzz/responses/video_details_response.rb
205
+ - lib/brainzz/responses/view_count_response.rb
206
+ - lib/brainzz/services/access_token_service.rb
181
207
  - license/gplv3.md
182
208
  - license/lgplv3.md
183
209
  - license/lgplv3.png
@@ -201,7 +227,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
201
227
  version: '0'
202
228
  requirements: []
203
229
  rubyforge_project:
204
- rubygems_version: 2.4.5
230
+ rubygems_version: 2.4.6
205
231
  signing_key:
206
232
  specification_version: 4
207
233
  summary: YouTube API interface