how_many 0.0.1 → 0.1.0

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 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