how_many 0.0.1 → 0.1.0

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: 38abb29c9d453fd4078012357db7173aeef5b609
4
- data.tar.gz: 324a862dd5f0792d7eb462cc6f07f138ea688cc7
3
+ metadata.gz: 12a9c6f32f4ee8e7d11277db9483378a5bfb8b47
4
+ data.tar.gz: 74d0a0742687ed7e4341607c88ea263f67198351
5
5
  SHA512:
6
- metadata.gz: 0b603c906a9a6aa532d2178091a506805d65fa5c70d1c606ed22a4e1569b8044d041df6b497a4e912a08f466c9e889dc617fc49daf7f36e8c012f7abcdf7582f
7
- data.tar.gz: f018626e4119c5c6371c63912a6d17b57ebebf4d0ddad259bf68891f7ae8775c720bd37285776705a3c493eda8e0cbcd1d977f575cc14f2653f8bac586baf9ba
6
+ metadata.gz: 6764d4cc3a2e3f583f67e10d587a3b6c8b6890471563cf6a580ab49f1fc25743245a54310613a48180c2b926beeb5c3748631b554c090ecd9c81ec55970951ed
7
+ data.tar.gz: 614aa5dc50fc09d1d34383f8d07ce4f26214515654ea5a18a40fd3012d788b45e3fa809b0ce33821fc17d54226b74e76064d786b4fa4afc2462d3219d810b628
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --fail-fast
data/.yardopts ADDED
@@ -0,0 +1,2 @@
1
+ --no-private
2
+ lib/**/*.rb
data/CHANGELOG.md ADDED
@@ -0,0 +1,11 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ For more information about changelogs, check
6
+ [Keep a Changelog](http://keepachangelog.com) and
7
+ [Vandamme](http://tech-angels.github.io/vandamme).
8
+
9
+ ## 0.1.0 - 2014-10-27
10
+
11
+ * [FEATURE] Initial release with `views(channel_id: ...)` method
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
1
  source 'https://rubygems.org'
2
-
2
+ gem 'pry'
3
3
  # Specify your gem's dependencies in how_many.gemspec
4
4
  gemspec
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014 claudiob
1
+ Copyright (c) 2014 Fullscreen Inc.
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -1,29 +1,104 @@
1
- # HowMany
1
+ How many views do the most recent videos of a YouTube channel have?
2
+ ===================================================================
2
3
 
3
- TODO: Write a gem description
4
+ HowMany helps you write apps that need to know how many times the videos of
5
+ a CMS-partnered YouTube channel were viewed.
4
6
 
5
- ## Installation
7
+ After [registering your app](#configuring-your-app), you can run the only
8
+ command currently provided by the gem:
6
9
 
7
- Add this line to your application's Gemfile:
10
+ ```ruby
11
+ HowMany.views channel_id: 'UCxO1tY8h1AhOz0T4ENwmpow' # => 139
12
+ ```
8
13
 
9
- gem 'how_many'
14
+ How to install
15
+ ==============
10
16
 
11
- And then execute:
17
+ To install on your system, run
12
18
 
13
- $ bundle
19
+ gem install how_many
14
20
 
15
- Or install it yourself as:
21
+ To use inside a bundled Ruby project, add this line to the Gemfile:
16
22
 
17
- $ gem install how_many
23
+ gem 'how_many', '~> 0.1.0'
18
24
 
19
- ## Usage
25
+ Since the gem follows [Semantic Versioning](http://semver.org),
26
+ indicating the full version in your Gemfile (~> *major*.*minor*.*patch*)
27
+ guarantees that your project won’t occur in any error when you `bundle update`
28
+ and a new version of HowMany is released.
20
29
 
21
- TODO: Write usage instructions here
30
+ Available methods
31
+ =================
22
32
 
23
- ## Contributing
33
+ views
34
+ -----
24
35
 
25
- 1. Fork it ( https://github.com/[my-github-username]/how_many/fork )
26
- 2. Create how_many feature branch (`git checkout -b my-new-feature`)
27
- 3. Commit how_many changes (`git commit -am 'Add some feature'`)
28
- 4. Push to the branch (`git push origin my-new-feature`)
29
- 5. Create a new Pull Request
36
+ Use `HowMany.views` to retrieve the median views for the videos of a channel:
37
+
38
+ ```ruby
39
+ require 'how_many'
40
+
41
+ # get the median views of the last videos of a Fullscreen-partnered channel
42
+ HowMany.views(channel_id: 'UCSBzN-I43cp0-xekSFW5mkQ')
43
+ #=> 12534.5
44
+
45
+ # get the same value for a channel with not enough videos
46
+ HowMany.views(channel_id: 'UCI7ajRBjOkCUvfQleFUfelA')
47
+ #=> raise error HowMany::NotEnoughVideos
48
+
49
+ # get the same value for PewDiePie
50
+ HowMany.views(channel_id: 'UC-lHJZR3Gqxm24_Vd_AJ5Yw')
51
+ #=> raise error HowMany::Unauthorized
52
+ ```
53
+
54
+ *The methods above require to be authenticated as a YouTube Content Partner account (see below).*
55
+
56
+
57
+ Configuring your app
58
+ ====================
59
+
60
+ In order to use HowMany you must be able to authenticate as a YouTube CMS owner.
61
+ You will only be able to retrieve the views for channels partnered with your CMS.
62
+
63
+ In the [Google Developers Console](https://console.developers.google.com),
64
+ find or create an app that can be used to obtain a refresh token for the
65
+ YouTube CMS owner.
66
+
67
+ Copy Client ID and Client secret from the app and add them together with the
68
+ refresh token to you code with the following initializer (replacing with your
69
+ own keys):
70
+
71
+ ```ruby
72
+ HowMany.configure do |config|
73
+ config.client_id = '1234567890.apps.googleusercontent.com'
74
+ config.client_secret = '1234567890'
75
+ config.refresh_token = '1/1234567890'
76
+ end
77
+ ```
78
+
79
+ As an alternative to the approach above, you can configure your app with
80
+ variables. Setting the following environment variables:
81
+
82
+ ```bash
83
+ export HOW_MANY_CLIENT_ID="1234567890.apps.googleusercontent.com"
84
+ export HOW_MANY_CLIENT_SECRET="1234567890"
85
+ export HOW_MANY_REFRESH_TOKEN="1/1234567890"
86
+ ```
87
+
88
+ is equivalent to the approach above.
89
+ If a variable is set in both places, then `HowMany.configure` takes precedence.
90
+
91
+
92
+ How to test
93
+ ===========
94
+
95
+ Set the following environment variables:
96
+
97
+ * `HOW_MANY_TEST_CLIENT_ID` the client ID of your registered YouTube app.
98
+ * `HOW_MANY_TEST_CLIENT_SECRET` the client secret of your registered YouTube app.
99
+ * `HOW_MANY_TEST_REFRESH_TOKEN` the refresh token of the test YouTube CMS user.
100
+
101
+ Then run `rspec`.
102
+
103
+ Whenever you change the code, make sure all the tests pass and the code
104
+ coverage is 100% before submitting a pull request. Thanks.
data/how_many.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'how_many/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "how_many"
8
+ spec.version = HowMany::VERSION
9
+ spec.authors = ["claudiob"]
10
+ spec.email = ["claudiob@gmail.com"]
11
+ spec.summary = %q{How many views does a YouTube channel have?}
12
+ spec.description = %q{Retrieve analytics data for YouTube channels.}
13
+ spec.homepage = "https://github.com/fullscreen/how_many"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ # To access YouTube API
22
+ spec.add_development_dependency 'yt', '~> 0.13.7'
23
+
24
+ # For development / Code coverage / Documentation
25
+ spec.add_development_dependency 'bundler', '~> 1.7'
26
+ spec.add_development_dependency 'rspec', '~> 3.1'
27
+ spec.add_development_dependency 'rake', '~> 10.3'
28
+ spec.add_development_dependency 'yard', '~> 0.8.7'
29
+ spec.add_development_dependency 'coveralls', '~> 0.7.1'
30
+ end
@@ -0,0 +1,76 @@
1
+ require 'yt'
2
+ require 'how_many/config'
3
+ require 'how_many/errors'
4
+
5
+ module HowMany
6
+ # Abstracts a YouTube channel.
7
+ class Channel
8
+ # Initialize a Channel instance.
9
+ def initialize(attrs = {})
10
+ @id = attrs[:channel_id]
11
+ @days = attrs.fetch :days, 14
12
+ @video_count = attrs.fetch :video_count, 10
13
+ end
14
+
15
+ # Return the unique YouTube channel ID.
16
+ attr_reader :id
17
+
18
+ # Return the number of days since a video was first published for which
19
+ # the number of views has to be retrieved.
20
+ attr_reader :days
21
+
22
+ # Return the number of videos for which the views have to be retrieved.
23
+ attr_reader :video_count
24
+
25
+ # Return the median number of views that the `@video_count` most recent
26
+ # videos of the channel have received in the first `@days` days since
27
+ # they were published. Excludes videos that were published less than
28
+ # `@days + 2` days ago, since analytics data might not be available yet.
29
+ def median_recent_video_views
30
+ raise NotEnoughVideos if yt_videos.size < video_count
31
+ views_by_day = yt_videos.map do |v|
32
+ v.views since: v.published_at, until: (v.published_at + days.days)
33
+ end
34
+ views_by_video = views_by_day.map(&:values).map(&:sum)
35
+ median views_by_video
36
+ end
37
+
38
+ private
39
+
40
+ def median(array)
41
+ (array[(array.length/2) - 1] + array[array.length/2]) / 2.to_f
42
+ end
43
+
44
+ def yt_videos
45
+ conditions = {published_before: (days + 2).days.ago.utc.iso8601(3)}
46
+ @yt_videos ||= yt_channel.videos.where(conditions).first(video_count)
47
+ rescue Yt::Errors::Forbidden
48
+ raise Unauthorized
49
+ end
50
+
51
+ def yt_channel
52
+ @yt_channel ||= Yt::Channel.new id: id, auth: yt_content_owner
53
+ end
54
+
55
+ def yt_content_owner
56
+ @yt_content_owner ||= yt_account.content_owners.find do |content_owner|
57
+ channel = Yt::Channel.new id: id, auth: content_owner
58
+ channel.content_owner == content_owner.owner_name
59
+ end
60
+ rescue Yt::Errors::MissingAuth
61
+ raise Unauthorized
62
+ end
63
+
64
+ def yt_account
65
+ @yt_account ||= Yt::Account.new refresh_token: refresh_token
66
+ end
67
+
68
+ def refresh_token
69
+ Yt.configure do |config|
70
+ config.client_id = HowMany.configuration.client_id
71
+ config.client_secret = HowMany.configuration.client_secret
72
+ end
73
+ HowMany.configuration.refresh_token
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,43 @@
1
+ require 'yt/models/configuration'
2
+
3
+ module HowMany
4
+ # Provides an object to store global configuration settings.
5
+ class Configuration
6
+ # @return [String] the Client ID for the CMS-enabled YouTube app.
7
+ # @see https://console.developers.google.com Google Developers Console
8
+ attr_accessor :client_id
9
+
10
+ # @return [String] the Client Secret for the CMS-enabled YouTube app.
11
+ # @see https://console.developers.google.com Google Developers Console
12
+ attr_accessor :client_secret
13
+
14
+ # @return [String] the refresh token for the CMS user.
15
+ attr_accessor :refresh_token
16
+
17
+ # Initialize the global configuration settings, using the values of
18
+ # the specified following environment variables by default.
19
+ def initialize
20
+ @client_id = ENV['HOW_MANY_CLIENT_ID']
21
+ @client_secret = ENV['HOW_MANY_CLIENT_SECRET']
22
+ @refresh_token = ENV['HOW_MANY_REFRESH_TOKEN']
23
+ end
24
+ end
25
+
26
+ # Provides methods to read and write global configuration settings.
27
+ module Config
28
+ # Yields the global configuration to the given block.
29
+ def configure
30
+ yield configuration if block_given?
31
+ end
32
+
33
+ # Returns the global {HowMany::Models::Configuration} object.
34
+ def configuration
35
+ @configuration ||= HowMany::Configuration.new
36
+ end
37
+ end
38
+
39
+ # @note Config is the only module auto-loaded in the HowMany module,
40
+ # in order to have a syntax as easy as HowMany.configure
41
+
42
+ extend Config
43
+ end
@@ -0,0 +1,15 @@
1
+ module HowMany
2
+ # Generic base Error
3
+ class Error < StandardError
4
+ end
5
+
6
+ # Raised when trying to calculate the median video views for a channel that
7
+ # does not have enough videos to calculate a valid median.
8
+ class NotEnoughVideos < Error
9
+ end
10
+
11
+ # Raised when trying to access the analytics of a channel for which the
12
+ # analytics cannot be accessed.
13
+ class Unauthorized < Error
14
+ end
15
+ end
@@ -1,3 +1,4 @@
1
1
  module HowMany
2
- VERSION = "0.0.1"
2
+ # Version of the how_many gem.
3
+ VERSION = '0.1.0'
3
4
  end
@@ -0,0 +1,14 @@
1
+ require 'how_many/channel'
2
+
3
+ module HowMany
4
+ # Return the median number of views of the videos of a YouTube channel.
5
+ # Valid options are: channel_id (unique identifier of a YouTube channel),
6
+ # days (the range of days for which to retrieve the video views) and
7
+ # video_count (for how many recent videos the median should be calculated).
8
+ def views(options = {})
9
+ channel = Channel.new options
10
+ channel.median_recent_video_views
11
+ end
12
+
13
+ module_function :views
14
+ end
data/lib/how_many.rb CHANGED
@@ -1,5 +1,5 @@
1
- require "how_many/version"
1
+ require 'how_many/views'
2
2
 
3
+ # Helps creating apps that need to retrieve view counts for YouTube videos.
3
4
  module HowMany
4
- # HowMany code goes here...
5
- end
5
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+ require 'how_many'
3
+
4
+ describe 'HowMany.views' do
5
+ subject(:channel_views) { HowMany.views channel_id: channel_id }
6
+
7
+ context 'after having authenticated as Fullscreen CMS' do
8
+ before do
9
+ HowMany.configure do |config|
10
+ config.client_id = ENV['HOW_MANY_TEST_CLIENT_ID']
11
+ config.client_secret = ENV['HOW_MANY_TEST_CLIENT_SECRET']
12
+ config.refresh_token = ENV['HOW_MANY_TEST_REFRESH_TOKEN']
13
+ end
14
+ end
15
+
16
+ context 'given a Fullscreen-partnered channels with many videos' do
17
+ let(:channel_id) { 'UCSBzN-I43cp0-xekSFW5mkQ' }
18
+ it { expect(channel_views).to be_a Float }
19
+ end
20
+
21
+ context 'given a Fullscreen-partnered channels with few videos' do
22
+ let(:channel_id) { 'UCjA3ooUo_j8r2d5a5g9YrVA' }
23
+ it { expect{channel_views}.to raise_error HowMany::NotEnoughVideos }
24
+ end
25
+
26
+ context 'given a non-Fullscreen-partnered channel' do
27
+ let(:channel_id) { 'UC-lHJZR3Gqxm24_Vd_AJ5Yw' }
28
+ it { expect{channel_views}.to raise_error HowMany::Unauthorized }
29
+ end
30
+ end
31
+
32
+ context 'without having authenticated' do
33
+ before do
34
+ HowMany.configure do |config|
35
+ config.client_id = nil
36
+ config.client_secret = nil
37
+ config.refresh_token = nil
38
+ end
39
+ end
40
+
41
+ context 'given any channel' do
42
+ let(:channel_id) { 'UCSBzN-I43cp0-xekSFW5mkQ' }
43
+ it { expect{channel_views}.to raise_error HowMany::Unauthorized }
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,15 @@
1
+ require 'simplecov'
2
+ require 'coveralls'
3
+
4
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
5
+ SimpleCov::Formatter::HTMLFormatter,
6
+ Coveralls::SimpleCov::Formatter
7
+ ]
8
+ SimpleCov.start
9
+
10
+ Dir['./spec/support/**/*.rb'].each {|f| require f}
11
+
12
+ RSpec.configure do |config|
13
+ config.order = 'random'
14
+ config.run_all_when_everything_filtered = false
15
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: how_many
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - claudiob
@@ -10,35 +10,91 @@ bindir: bin
10
10
  cert_chain: []
11
11
  date: 2014-10-27 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: yt
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.13.7
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.13.7
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
31
  - - "~>"
18
32
  - !ruby/object:Gem::Version
19
- version: '1.6'
33
+ version: '1.7'
20
34
  type: :development
21
35
  prerelease: false
22
36
  version_requirements: !ruby/object:Gem::Requirement
23
37
  requirements:
24
38
  - - "~>"
25
39
  - !ruby/object:Gem::Version
26
- version: '1.6'
40
+ version: '1.7'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.1'
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: rake
29
57
  requirement: !ruby/object:Gem::Requirement
30
58
  requirements:
31
- - - ">="
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.3'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: yard
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
32
74
  - !ruby/object:Gem::Version
33
- version: '0'
75
+ version: 0.8.7
34
76
  type: :development
35
77
  prerelease: false
36
78
  version_requirements: !ruby/object:Gem::Requirement
37
79
  requirements:
38
- - - ">="
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.8.7
83
+ - !ruby/object:Gem::Dependency
84
+ name: coveralls
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.7.1
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
39
95
  - !ruby/object:Gem::Version
40
- version: '0'
41
- description: Write a longer description. Optional.
96
+ version: 0.7.1
97
+ description: Retrieve analytics data for YouTube channels.
42
98
  email:
43
99
  - claudiob@gmail.com
44
100
  executables: []
@@ -46,14 +102,23 @@ extensions: []
46
102
  extra_rdoc_files: []
47
103
  files:
48
104
  - ".gitignore"
105
+ - ".rspec"
106
+ - ".yardopts"
107
+ - CHANGELOG.md
49
108
  - Gemfile
50
109
  - LICENSE.txt
51
110
  - README.md
52
111
  - Rakefile
53
- - how_many,.gemspec
112
+ - how_many.gemspec
54
113
  - lib/how_many.rb
114
+ - lib/how_many/channel.rb
115
+ - lib/how_many/config.rb
116
+ - lib/how_many/errors.rb
55
117
  - lib/how_many/version.rb
56
- homepage: ''
118
+ - lib/how_many/views.rb
119
+ - spec/how_many/views_spec.rb
120
+ - spec/spec_helper.rb
121
+ homepage: https://github.com/fullscreen/how_many
57
122
  licenses:
58
123
  - MIT
59
124
  metadata: {}
@@ -76,5 +141,8 @@ rubyforge_project:
76
141
  rubygems_version: 2.2.2
77
142
  signing_key:
78
143
  specification_version: 4
79
- summary: Write a short summary. Required.
80
- test_files: []
144
+ summary: How many views does a YouTube channel have?
145
+ test_files:
146
+ - spec/how_many/views_spec.rb
147
+ - spec/spec_helper.rb
148
+ has_rdoc:
data/how_many,.gemspec DELETED
@@ -1,23 +0,0 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'how_many/version'
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "how_many"
8
- spec.version = HowMany::VERSION
9
- spec.authors = ["claudiob"]
10
- spec.email = ["claudiob@gmail.com"]
11
- spec.summary = %q{Write a short summary. Required.}
12
- spec.description = %q{Write a longer description. Optional.}
13
- spec.homepage = ""
14
- spec.license = "MIT"
15
-
16
- spec.files = `git ls-files -z`.split("\x0")
17
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ["lib"]
20
-
21
- spec.add_development_dependency "bundler", "~> 1.6"
22
- spec.add_development_dependency "rake"
23
- end