dm 0.0.1
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +211 -0
- data/lib/dm.rb +3 -0
- data/lib/dm/authenticable.rb +96 -0
- data/lib/dm/client_tokens.rb +22 -0
- data/lib/dm/google_account.rb +74 -0
- data/lib/dm/readable.rb +30 -0
- data/lib/dm/requestable.rb +58 -0
- data/lib/dm/server_tokens.rb +11 -0
- data/lib/dm/version.rb +3 -0
- data/lib/dm/youtube_account.rb +78 -0
- data/lib/dm/youtube_resource.rb +86 -0
- metadata +127 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: a3efcb21d39dea62767ab57939fa1f54091e9532
|
|
4
|
+
data.tar.gz: 4770202bbf71cd96f77723b99453f42017e6f515
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: c436618bebbaa74e240177b71983ba5c81c0b2efbb526f90d32fca6091f64d16dd9c67862dbfb4ab504dbf8b4484c8b458716973199b2e81dada7a258f1313d8
|
|
7
|
+
data.tar.gz: c366cb0e09b3db776d24157604cf6b2a3af00f7f679ef14ea829ee22af71f85030c878106d417e289b038cf69523153a540f7ff4a8e02ab33d488003687a1d50
|
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright 2014 claudiob
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
Dm
|
|
2
|
+
======
|
|
3
|
+
|
|
4
|
+
Dm lets you interact with many resources provided by DailyMotion API V3.
|
|
5
|
+
|
|
6
|
+
[](https://travis-ci.org/claudiob/dm)
|
|
7
|
+
[](https://codeclimate.com/github/claudiob/dm)
|
|
8
|
+
[](https://coveralls.io/r/claudiob/dm)
|
|
9
|
+
[](https://gemnasium.com/claudiob/dm)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
```ruby
|
|
13
|
+
channel = Dm::DailyMotionResource.new url: 'dailymotion.com/remhq'
|
|
14
|
+
channel.id #=> 'UC7eaRqtonpyiYw0Pns0Au_g'
|
|
15
|
+
channel.title #=> "remhq"
|
|
16
|
+
channel.description #=> "R.E.M.'s Official DailyMotion Channel"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```ruby
|
|
20
|
+
video = Dm::DailyMotionResource.new url: 'youtu.be/Kd5M17e7Wek'
|
|
21
|
+
video.id #=> 'Kd5M17e7Wek'
|
|
22
|
+
video.title #=> "R.E.M. - Tongue (Video)"
|
|
23
|
+
video.description #=> "© 2006 WMG\nTongue (Video)"
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
```ruby
|
|
27
|
+
account = Dm::DailyMotionAccount.new auth_params
|
|
28
|
+
account.email #=> 'user@google.com'
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```ruby
|
|
32
|
+
account = Dm::DailyMotionAccount.new auth_params
|
|
33
|
+
account.perform! :like, :video, 'Kd5M17e7Wek' # => adds 'Tongue' to your 'Liked videos'
|
|
34
|
+
account.perform! :subscribe_to, :channel, 'UC7eaRqtonpyiYw0Pns0Au_g' # => subscribes to R.E.M.’s channel
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The full documentation is available at [rubydoc.info](http://rubydoc.info/github/claudiob/dm/master/frames).
|
|
38
|
+
|
|
39
|
+
Available classes
|
|
40
|
+
=================
|
|
41
|
+
|
|
42
|
+
Dm exposes three different resources provided by DailyMotion API V3:
|
|
43
|
+
DailyMotion Accounts, DailyMotion Accounts and DailyMotion Resources.
|
|
44
|
+
|
|
45
|
+
DailyMotion accounts
|
|
46
|
+
---------------
|
|
47
|
+
|
|
48
|
+
Use `Dm::DailyMotionAccount` to send and retrieve data to DailyMotion,
|
|
49
|
+
impersonating an existing DailyMotion account. Available methods:
|
|
50
|
+
|
|
51
|
+
* `email`: returns the email of a DailyMotion account
|
|
52
|
+
* `name`: returns the name of a DailyMotion account
|
|
53
|
+
|
|
54
|
+
These methods require user authentication (see below).
|
|
55
|
+
|
|
56
|
+
DailyMotion accounts
|
|
57
|
+
----------------
|
|
58
|
+
|
|
59
|
+
Use `Dm::DailyMotionAccount` to send and retrieve data to DailyMotion,
|
|
60
|
+
impersonating an existing DailyMotion account. Available methods:
|
|
61
|
+
|
|
62
|
+
* `perform!`: executes promotion actions such as: liking a video, subscribing to a channel
|
|
63
|
+
|
|
64
|
+
These methods require user authentication (see below).
|
|
65
|
+
|
|
66
|
+
DailyMotion resources
|
|
67
|
+
-----------------
|
|
68
|
+
|
|
69
|
+
Use `Dm::DailyMotionResource` to retrieve read-only information about
|
|
70
|
+
public DailyMotion channels and videos. Available methods:
|
|
71
|
+
|
|
72
|
+
* `id`: returns the unique identifier of a DailyMotion channel/video
|
|
73
|
+
* `title`: returns the title of a DailyMotion channel/video
|
|
74
|
+
* `description`: returns the description of a DailyMotion channel/video
|
|
75
|
+
* `thubmnail_url`: returns the URL of the thumbnail of a DailyMotion channel/video
|
|
76
|
+
|
|
77
|
+
These methods require do not require user authentication.
|
|
78
|
+
|
|
79
|
+
Authentication
|
|
80
|
+
==============
|
|
81
|
+
|
|
82
|
+
In order to use Dm you must register your app in the [DailyMotion Developers Console](https://console.developers.google.com):
|
|
83
|
+
|
|
84
|
+
1. Create a new app and enable access to DailyMotion+ API and DailyMotion Data API V3
|
|
85
|
+
1. Generate a new OAuth client ID (web application) and write down the `client ID` and `client secret`
|
|
86
|
+
1. Generate a new Public API access key (for server application) and write down the `server key`
|
|
87
|
+
|
|
88
|
+
Run the following command to make these tokens available to Dm:
|
|
89
|
+
|
|
90
|
+
```ruby
|
|
91
|
+
require 'dm'
|
|
92
|
+
Dm.authenticate_with client_id: '...', client_secret: '...', server_key: '...'
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
replacing the ellipses with the values from the DailyMotion Developers Console.
|
|
96
|
+
|
|
97
|
+
For actions that impersonate a DailyMotion or DailyMotion account, you also need to
|
|
98
|
+
obtain authorization from the owner of the account you wish to impersonate:
|
|
99
|
+
|
|
100
|
+
1. In your web site, add a link to the DailyMotion's OAuth login page. The URL is:
|
|
101
|
+
|
|
102
|
+
```ruby
|
|
103
|
+
Dm::DailyMotionAccount.oauth_url(url) # to impersonate a DailyMotion Account
|
|
104
|
+
Dm::DailyMotionAccount.oauth_url(url) # to impersonate a DailyMotion Account
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
1. Upon authorization, the user is redirected to the URL passed as an argument, with an extra 'code' query parameter which can be used to impersonate the account:
|
|
108
|
+
|
|
109
|
+
```ruby
|
|
110
|
+
account = Dm::DailyMotionAccount.new(code: code, redirect_uri: url) # to impersonate a DailyMotion Account
|
|
111
|
+
account = Dm::DailyMotionAccount.new(code: code, redirect_uri: url) # to impersonate a DailyMotion Account
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
1. To prevent the user from having to authorize the app every time, store the account’s refresh_token in your database:
|
|
115
|
+
|
|
116
|
+
```ruby
|
|
117
|
+
refresh_token = account.credentials[:refresh_token] # Store to your DB
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
1. To impersonate an account that has already authorized your app, just use the refresh_token:
|
|
121
|
+
|
|
122
|
+
```ruby
|
|
123
|
+
account = Dm::DailyMotionAccount.new(refresh_token: refresh_token) # to impersonate a DailyMotion Account
|
|
124
|
+
account = Dm::DailyMotionAccount.new(refresh_token: refresh_token) # to impersonate a DailyMotion Account
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Remember that the redirect URL you use in the app must also be registered in
|
|
128
|
+
the DailyMotion Developers Console.
|
|
129
|
+
Also, remember to set a Product name for your app in the DailyMotion Developers
|
|
130
|
+
Console, under API & Auth > Consent screen.
|
|
131
|
+
|
|
132
|
+
How to install
|
|
133
|
+
==============
|
|
134
|
+
|
|
135
|
+
To install on your system, run
|
|
136
|
+
|
|
137
|
+
gem install dm
|
|
138
|
+
|
|
139
|
+
To use inside a bundled Ruby project, add this line to the Gemfile:
|
|
140
|
+
|
|
141
|
+
gem 'dm', '~> 0.1.0'
|
|
142
|
+
|
|
143
|
+
The dm gem follows [Semantic Versioning](http://semver.org).
|
|
144
|
+
Any new release that is fully backward-compatible bumps the *patch* version (0.0.x).
|
|
145
|
+
Any new version that breaks compatibility bumps the *minor* version (0.x.0)
|
|
146
|
+
|
|
147
|
+
Indicating the full version in your Gemfile (*major*.*minor*.*patch*) guarantees
|
|
148
|
+
that your project won’t occur in any error when you `bundle update` and a new
|
|
149
|
+
version of Dm is released.
|
|
150
|
+
|
|
151
|
+
Why you should use Dm…
|
|
152
|
+
--------------------------
|
|
153
|
+
|
|
154
|
+
… and not [dailymotion_it](https://github.com/kylejginavan/dailymotion_it)?
|
|
155
|
+
Because dailymotion_it does not support DailyMotion API V3 and the previous version
|
|
156
|
+
has already been deprecated by DailyMotion and will soon be dropped.
|
|
157
|
+
|
|
158
|
+
… and not [DailyMotion Api Client](https://github.com/google/google-api-ruby-client)?
|
|
159
|
+
Because DailyMotion Api Client is poorly coded, poorly documented and adds many
|
|
160
|
+
dependencies, bloating the size of your project.
|
|
161
|
+
|
|
162
|
+
… and not your own code? Because Dm is fully tested, well documented,
|
|
163
|
+
has few dependencies and helps you forget about the burden of dealing with
|
|
164
|
+
DailyMotion API!
|
|
165
|
+
|
|
166
|
+
How to test
|
|
167
|
+
===========
|
|
168
|
+
|
|
169
|
+
To run the tests, you must give the test app permissions to access your
|
|
170
|
+
DailyMotion and DailyMotion accounts. They are free, so feel free to create a fake one.
|
|
171
|
+
|
|
172
|
+
1. Run the following commands in a ruby session:
|
|
173
|
+
|
|
174
|
+
```ruby
|
|
175
|
+
require 'dm'
|
|
176
|
+
Dm::DailyMotionAccount.oauth_url # => "https://accounts.google.com/o..."
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
1. Copy the last URL in a browser, and accept the terms. You will be redirected to a URL like http://example.com/?code=ABCDE
|
|
180
|
+
|
|
181
|
+
1. Copy the `code` parameter (ABCDE in the example above) and run:
|
|
182
|
+
|
|
183
|
+
```ruby
|
|
184
|
+
account = Dm::DailyMotionAccount.new code: 'ABCDE'
|
|
185
|
+
account.credentials[:refresh_token]
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
1. Copy the token returned by the last command (something like 1AUJZh2x1...) and store it in an environment variable before running the test suite:
|
|
189
|
+
|
|
190
|
+
```ruby
|
|
191
|
+
export GOOGOL_TEST_GOOGLE_REFRESH_TOKEN="1AUJZh2x1..."
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
1. Repeat all the steps above replacing DailyMotionAccount with DailyMotionAccount to authorize access to your DailyMotion account:
|
|
195
|
+
|
|
196
|
+
```ruby
|
|
197
|
+
export GOOGOL_TEST_YOUTUBE_REFRESH_TOKEN="2B6T5x23..."
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
1. Finally run the tests running `rspec` or `rake`. If you prefer not to set environment variables, pass the refresh token in the same line:
|
|
201
|
+
|
|
202
|
+
```ruby
|
|
203
|
+
GOOGOL_TEST_GOOGLE_REFRESH_TOKEN="1AUJZh2x1..." GOOGOL_TEST_YOUTUBE_REFRESH_TOKEN="2B6T5x23..." rspec
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
How to contribute
|
|
207
|
+
=================
|
|
208
|
+
|
|
209
|
+
Don’t hesitate to send code comments, issues or pull requests through GitHub!
|
|
210
|
+
|
|
211
|
+
All feedback is appreciated. A [dm](http://en.wikipedia.org/wiki/Dm) of thanks! :)
|
data/lib/dm.rb
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
require 'uri'
|
|
2
|
+
require 'cgi'
|
|
3
|
+
require 'dm/client_tokens'
|
|
4
|
+
require 'dm/requestable'
|
|
5
|
+
|
|
6
|
+
module Dm
|
|
7
|
+
# Provides methods to authenticate as an account (either DailyMotion or DailyMotion).
|
|
8
|
+
module Authenticable
|
|
9
|
+
include ClientTokens
|
|
10
|
+
include Requestable
|
|
11
|
+
|
|
12
|
+
# Initialize an object with either an authorization code or a refresh token
|
|
13
|
+
#
|
|
14
|
+
# @see https://developers.google.com/accounts/docs/OAuth2
|
|
15
|
+
#
|
|
16
|
+
# @param [Hash] attrs Authentication credentials to access the account
|
|
17
|
+
# @option attrs [String] :code The OAuth2 authorization code
|
|
18
|
+
# @option attrs [String] :redirect_url The page to redirect after the OAuth2 page
|
|
19
|
+
# @option attrs [String] :refresh_token The refresh token for offline access
|
|
20
|
+
def initialize(attrs = {})
|
|
21
|
+
@code = attrs[:code]
|
|
22
|
+
@refresh_token = attrs[:refresh_token]
|
|
23
|
+
@redirect_url = attrs.fetch :redirect_url, 'http://example.com/'
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Return the authorization credentials of an account for this app.
|
|
27
|
+
#
|
|
28
|
+
# @see ...
|
|
29
|
+
#
|
|
30
|
+
# @return [Hash]
|
|
31
|
+
# * :client_id [String] ...
|
|
32
|
+
# * :client_secret [String] ...
|
|
33
|
+
# * ...
|
|
34
|
+
def credentials
|
|
35
|
+
@credentials ||= request! method: :post,
|
|
36
|
+
host: 'https://accounts.google.com',
|
|
37
|
+
path: '/o/oauth2/token',
|
|
38
|
+
body: credentials_params,
|
|
39
|
+
valid_if: -> response, body {response.code == '200'}
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
# Provides the credentials to access DailyMotion API as an authorized user.
|
|
45
|
+
#
|
|
46
|
+
# There are ways to do this:
|
|
47
|
+
# - For first-time users (who do not have a refresh token but only an
|
|
48
|
+
# authorization code): the code is submitted to DailyMotion to obtain an
|
|
49
|
+
# access token (to use immediately) and a refresh_token
|
|
50
|
+
# - For existing users (who have a refresh token): the refresh token is
|
|
51
|
+
# submitted to DailyMotion to obtain a new access token
|
|
52
|
+
def credentials_params
|
|
53
|
+
if @refresh_token
|
|
54
|
+
{grant_type: :refresh_token, refresh_token: @refresh_token}
|
|
55
|
+
else
|
|
56
|
+
{grant_type: :authorization_code, code: @code, redirect_uri: @redirect_url}
|
|
57
|
+
end.merge client_id: client_id, client_secret: client_secret
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def self.included(base)
|
|
61
|
+
base.extend ClassMethods
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
module ClassMethods
|
|
65
|
+
include ClientTokens
|
|
66
|
+
# Returns the URL for users to authorize this app to access their account
|
|
67
|
+
#
|
|
68
|
+
# @param [String] redirect_url The page to redirect after the OAuth2 page
|
|
69
|
+
#
|
|
70
|
+
# @return [String] URL of the OAuth2 Authorization page.
|
|
71
|
+
#
|
|
72
|
+
# @note The redirect_url *must* match one of the redirect URLs whitelisted
|
|
73
|
+
# for the app in the DailyMotion Developers Console
|
|
74
|
+
#
|
|
75
|
+
# @see https://console.developers.google.com
|
|
76
|
+
def oauth_url(redirect_url = 'http://example.com/')
|
|
77
|
+
params = {
|
|
78
|
+
client_id: client_id,
|
|
79
|
+
scope: oauth_scopes.join(' '),
|
|
80
|
+
redirect_uri: redirect_url,
|
|
81
|
+
response_type: :code,
|
|
82
|
+
access_type: :offline,
|
|
83
|
+
approval_prompt: :force
|
|
84
|
+
}
|
|
85
|
+
q = params.map{|k,v| "#{CGI.escape k.to_s}=#{CGI.escape v.to_s}"}.join '&'
|
|
86
|
+
args = {host: 'accounts.google.com', path: '/o/oauth2/auth', query: q}
|
|
87
|
+
URI::HTTPS.build(args).to_s
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Set the scopes to grant access to an account.
|
|
91
|
+
# This method is meant to be overridden.
|
|
92
|
+
def oauth_scopes
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Dm
|
|
2
|
+
module ClientTokens
|
|
3
|
+
@@client_id = '461491672627.apps.googleusercontent.com'
|
|
4
|
+
@@client_secret = 'qXRBFZyL9X0NHMEJ_9ItefC3'
|
|
5
|
+
|
|
6
|
+
def client_id
|
|
7
|
+
@@client_id
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def client_secret
|
|
11
|
+
@@client_secret
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.client_id=(client_id)
|
|
15
|
+
@@client_id = client_id
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.client_secret=(client_secret)
|
|
19
|
+
@@client_secret = client_secret
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
require 'dm/authenticable'
|
|
2
|
+
|
|
3
|
+
module Dm
|
|
4
|
+
# Provides read & write access to a DailyMotion (or DailyMotion+) account.
|
|
5
|
+
#
|
|
6
|
+
# @example Retrieve the email and given name of a DailyMotion account:
|
|
7
|
+
# * Set up two pages: one with a link to authenticate, one to redirect to
|
|
8
|
+
# * In the first page, add a link to the authentication page:
|
|
9
|
+
#
|
|
10
|
+
# Dm::DailyMotionAccount.oauth_url(redirect_url)
|
|
11
|
+
#
|
|
12
|
+
# * The user authenticates and lands on the second page, with an extra +code+ query parameter
|
|
13
|
+
# * Use the authorization code to initialize the DailyMotionAccount and retrieve information:
|
|
14
|
+
#
|
|
15
|
+
# account = Dm::DailyMotionAccount.new code: code, redirect_url: redirect_url
|
|
16
|
+
# account.email # => 'user@example.com'
|
|
17
|
+
# account.given_name # => 'Example user'
|
|
18
|
+
#
|
|
19
|
+
class DailyMotionAccount
|
|
20
|
+
include Authenticable
|
|
21
|
+
# Return the profile info of a DailyMotion account in OpenID Connect format.
|
|
22
|
+
#
|
|
23
|
+
# @see https://developers.google.com/+/api/latest/people/getOpenIdConnect
|
|
24
|
+
#
|
|
25
|
+
# @return [Hash]
|
|
26
|
+
# * :id [String] The ID of the authenticated account
|
|
27
|
+
# * :email [String] The account’s email address.
|
|
28
|
+
# * :verified_email [String] Boolean flag which is true if the email address is verified.
|
|
29
|
+
# * :name [String] The account’s full name.
|
|
30
|
+
# * :given_name [String] The account’s given (first) name.
|
|
31
|
+
# * :family_name [String] The account’s family (last) name.
|
|
32
|
+
# * :link [String] The URL of the account’s profile page.
|
|
33
|
+
# * :picture [String] The URL of the account’s profile picture.
|
|
34
|
+
# * :gender [String] The account’s gender
|
|
35
|
+
# * :locale [String] The account’s preferred locale.
|
|
36
|
+
# * :hd [String] The hosted domain name for the accounts’s DailyMotion Apps.
|
|
37
|
+
def info
|
|
38
|
+
@info ||= request! method: :get,
|
|
39
|
+
auth: credentials[:access_token],
|
|
40
|
+
host: 'https://www.googleapis.com',
|
|
41
|
+
path: '/oauth2/v2/userinfo',
|
|
42
|
+
valid_if: -> response, body {response.code == '200'}
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Define a method to return each attribute of the profile separately.
|
|
46
|
+
#
|
|
47
|
+
# @macro [attach] attribute.name
|
|
48
|
+
# @method $1()
|
|
49
|
+
# Return the $1 attribute of the DailyMotion Account.
|
|
50
|
+
#
|
|
51
|
+
def self.attribute(name)
|
|
52
|
+
define_method(name) { info[name] }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
attribute :id
|
|
56
|
+
attribute :email
|
|
57
|
+
attribute :verified_email
|
|
58
|
+
attribute :name
|
|
59
|
+
attribute :given_name
|
|
60
|
+
attribute :family_name
|
|
61
|
+
attribute :link
|
|
62
|
+
attribute :picture
|
|
63
|
+
attribute :gender
|
|
64
|
+
attribute :locale
|
|
65
|
+
attribute :hd
|
|
66
|
+
|
|
67
|
+
# Set the scopes to grant access to DailyMotion user profile and email
|
|
68
|
+
#
|
|
69
|
+
# @see https://developers.google.com/+/api/oauth#profile
|
|
70
|
+
def self.oauth_scopes
|
|
71
|
+
%w(profile email)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
data/lib/dm/readable.rb
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Dm
|
|
2
|
+
# Provides methods to read attributes for public objects (accounts, videos..)
|
|
3
|
+
module Readable
|
|
4
|
+
|
|
5
|
+
# Return the unique DailyMotion identifier of a DailyMotion object
|
|
6
|
+
def id
|
|
7
|
+
info[:id]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Return the title of a DailyMotion object
|
|
11
|
+
def title
|
|
12
|
+
info[:snippet][:title]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Return the description of a DailyMotion object
|
|
16
|
+
def description
|
|
17
|
+
info[:snippet][:description]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Return the URL of the DailyMotion object thumbnail
|
|
21
|
+
def thumbnail_url
|
|
22
|
+
info[:snippet][:thumbnails][:default][:url]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Return the kind of the DailyMotion object (either 'channel' or 'video')
|
|
26
|
+
def kind
|
|
27
|
+
info.fetch(:kind, '').split("#").last
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require 'uri'
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
4
|
+
module Dm
|
|
5
|
+
# A custom class to rescue errors from interacting with DailyMotion V3 API
|
|
6
|
+
class RequestError < StandardError
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Provides methods to send HTTP requests to DailyMotion V3 API
|
|
10
|
+
module Requestable
|
|
11
|
+
##
|
|
12
|
+
# Executes an HTTP request against the DailyMotion V3 API and returns the
|
|
13
|
+
# parsed result or raise an error in case of failure
|
|
14
|
+
#
|
|
15
|
+
def request!(params = {})
|
|
16
|
+
url = URI.parse params[:host]
|
|
17
|
+
http = Net::HTTP.new url.host, url.port
|
|
18
|
+
http.use_ssl = true
|
|
19
|
+
request = case params[:method]
|
|
20
|
+
when :get then Net::HTTP::Get.new params[:path]
|
|
21
|
+
when :post then
|
|
22
|
+
if params[:json]
|
|
23
|
+
Net::HTTP::Post.new params[:path], initheader = {'Content-Type' =>'application/json'}
|
|
24
|
+
else
|
|
25
|
+
Net::HTTP::Post.new params[:path]
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
if params[:json]
|
|
29
|
+
request.body = params[:body].to_json
|
|
30
|
+
else
|
|
31
|
+
request.set_form_data params[:body]
|
|
32
|
+
end if params[:body]
|
|
33
|
+
|
|
34
|
+
request['Authorization'] = 'Bearer ' + params[:auth] if params[:auth]
|
|
35
|
+
response = http.request(request)
|
|
36
|
+
|
|
37
|
+
body = JSON.parse response.body if response.body
|
|
38
|
+
|
|
39
|
+
if params[:valid_if] ? params[:valid_if].call(response, body) : true
|
|
40
|
+
body = params[:extract].call body if params[:extract]
|
|
41
|
+
body ? deep_symbolize_keys(body) : true
|
|
42
|
+
else
|
|
43
|
+
raise RequestError, body
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def deep_symbolize_keys(hash)
|
|
50
|
+
{}.tap do |result|
|
|
51
|
+
hash.each do |k, v|
|
|
52
|
+
key = k.to_sym rescue k
|
|
53
|
+
result[key] = v.is_a?(Hash) ? deep_symbolize_keys(v) : v
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
data/lib/dm/version.rb
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
require 'dm/authenticable'
|
|
2
|
+
require 'dm/readable'
|
|
3
|
+
|
|
4
|
+
module Dm
|
|
5
|
+
# Provides read & write access to a DailyMotion account (also known as Channel).
|
|
6
|
+
#
|
|
7
|
+
# @example Like the video "Tongue" by R.E.M. as a specific DailyMotion account:
|
|
8
|
+
# * Set up two pages: one with a link to authenticate, one to redirect to
|
|
9
|
+
# * In the first page, add a link to the authentication page:
|
|
10
|
+
#
|
|
11
|
+
# Dm::DailyMotionAccount.oauth_url(redirect_url)
|
|
12
|
+
#
|
|
13
|
+
# * The user authenticates and lands on the second page, with an extra +code+ query parameter
|
|
14
|
+
# * Use the authorization code to initialize the DailyMotionAccount and like the video:
|
|
15
|
+
#
|
|
16
|
+
# account = Dm::DailyMotionAccount.new code: code, redirect_url: redirect_url
|
|
17
|
+
# account.perform! :like, :video, 'Kd5M17e7Wek' # => likes the video
|
|
18
|
+
#
|
|
19
|
+
class DailyMotionAccount
|
|
20
|
+
include Authenticable
|
|
21
|
+
include Readable
|
|
22
|
+
# Return the profile info of a DailyMotion account/channel.
|
|
23
|
+
#
|
|
24
|
+
# @see https://developers.google.com/dailymotion/v3/docs/channels#resource
|
|
25
|
+
#
|
|
26
|
+
# @return [Hash]
|
|
27
|
+
# * :id [String] The ID that DailyMotion uses to uniquely identify the channel.
|
|
28
|
+
# * :etag [String] The Etag of this resource.
|
|
29
|
+
# * :kind [String] The value will be dailymotion#channel.
|
|
30
|
+
# * :snippet [Hash]
|
|
31
|
+
# - :title [String] The channel's title.
|
|
32
|
+
# - :description [String] The channel's description.
|
|
33
|
+
# - :publishedAt [String] The date and time that the channel was created. The value is specified in ISO 8601 (YYYY-MM-DDThh:mm:ss.sZ) format.
|
|
34
|
+
# - :thumbnails [Hash]
|
|
35
|
+
# + :default [Hash] Default thumbnail URL (88px x 88px)
|
|
36
|
+
# + :medium [Hash] Medium thumbnail URL (88px x 88px)
|
|
37
|
+
# + :high [Hash] High thumbnail URL (88px x 88px)
|
|
38
|
+
def info
|
|
39
|
+
@info ||= request! method: :get,
|
|
40
|
+
auth: credentials[:access_token],
|
|
41
|
+
host: 'https://www.googleapis.com',
|
|
42
|
+
path: '/dailymotion/v3/channels?part=id,snippet&mine=true',
|
|
43
|
+
valid_if: -> resp, body {resp.code == '200' && body['items'].any?},
|
|
44
|
+
extract: -> body {body['items'].first}
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
## Promote a DailyMotion target resource on this DailyMotion Channel
|
|
48
|
+
# Note that liking a video does not also subscribe to a channel
|
|
49
|
+
def perform!(activity, target_kind, target_id)
|
|
50
|
+
params = {}.tap do |params|
|
|
51
|
+
params[:method] = :post
|
|
52
|
+
params[:auth] = credentials[:access_token]
|
|
53
|
+
params[:host] = 'https://www.googleapis.com'
|
|
54
|
+
|
|
55
|
+
case [activity.to_sym, target_kind.to_sym]
|
|
56
|
+
when [:like, :video]
|
|
57
|
+
params[:path] = "/dailymotion/v3/videos/rate?rating=like&id=#{target_id}"
|
|
58
|
+
params[:valid_if] = -> response, body {response.code == '204'}
|
|
59
|
+
when [:subscribe_to, :channel]
|
|
60
|
+
params[:json] = true
|
|
61
|
+
params[:path] = '/dailymotion/v3/subscriptions?part=snippet'
|
|
62
|
+
params[:body] = {snippet: {resourceId: {channelId: target_id}}}
|
|
63
|
+
params[:valid_if] = -> response, body {response.code == '200'}
|
|
64
|
+
else
|
|
65
|
+
raise RequestError, "#{activity} invalid for #{target_kind} #{target_id}"
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
request! params
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Set the scopes to grant access to DailyMotion account
|
|
72
|
+
#
|
|
73
|
+
# @see https://developers.google.com/dailymotion/v3/guides/authentication
|
|
74
|
+
def self.oauth_scopes
|
|
75
|
+
%w(https://www.googleapis.com/auth/dailymotion)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
require 'dm/requestable'
|
|
2
|
+
require 'dm/readable'
|
|
3
|
+
require 'dm/server_tokens'
|
|
4
|
+
|
|
5
|
+
module Dm
|
|
6
|
+
# Provides read-only access to a DailyMotion resource (a channel or a video).
|
|
7
|
+
#
|
|
8
|
+
# @example Get the description of the video "Tongue" by R.E.M.:
|
|
9
|
+
#
|
|
10
|
+
# resource = Dm::DailyMotionResource.new url: 'youtu.be/Kd5M17e7Wek'
|
|
11
|
+
# resource.description # => "© 2006 WMG\nTongue (Video)"
|
|
12
|
+
#
|
|
13
|
+
# @example Get the description of the R.E.M. channel:
|
|
14
|
+
#
|
|
15
|
+
# resource = Dm::DailyMotionResource.new url: 'dailymotion.com/remhq'
|
|
16
|
+
# resource.description # => "R.E.M.'s Official DailyMotion Channel"
|
|
17
|
+
#
|
|
18
|
+
# Note that this class does not require the user to authenticate.
|
|
19
|
+
#
|
|
20
|
+
class DailyMotionResource
|
|
21
|
+
include Requestable
|
|
22
|
+
include Readable
|
|
23
|
+
include ServerTokens
|
|
24
|
+
# Initialize a resource by URL
|
|
25
|
+
#
|
|
26
|
+
# @param [Hash] attrs
|
|
27
|
+
# @option attrs [String] :url The URL of the DailyMotion channel or video
|
|
28
|
+
def initialize(attrs = {})
|
|
29
|
+
@url = attrs[:url]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Return the profile info of a DailyMotion account/channel.
|
|
33
|
+
#
|
|
34
|
+
# @see https://developers.google.com/dailymotion/v3/docs/channels#resource
|
|
35
|
+
#
|
|
36
|
+
# @return [Hash]
|
|
37
|
+
# * :id [String] The ID that DailyMotion uses to uniquely identify the channel.
|
|
38
|
+
# * :etag [String] The Etag of this resource.
|
|
39
|
+
# * :kind [String] The value will be dailymotion#channel.
|
|
40
|
+
# * :snippet [Hash]
|
|
41
|
+
# - :title [String] The channel's title.
|
|
42
|
+
# - :description [String] The channel's description.
|
|
43
|
+
# - :publishedAt [String] The date and time that the channel was created. The value is specified in ISO 8601 (YYYY-MM-DDThh:mm:ss.sZ) format.
|
|
44
|
+
# - :thumbnails [Hash]
|
|
45
|
+
# + :default [Hash] Default thumbnail URL (88px x 88px)
|
|
46
|
+
# + :medium [Hash] Medium thumbnail URL (88px x 88px)
|
|
47
|
+
# + :high [Hash] High thumbnail URL (88px x 88px)
|
|
48
|
+
def info
|
|
49
|
+
@info ||= request! method: :get,
|
|
50
|
+
host: 'https://www.googleapis.com',
|
|
51
|
+
path: "/dailymotion/v3/#{info_path}",
|
|
52
|
+
valid_if: -> resp, body {resp.code == '200' && body['items'].any?},
|
|
53
|
+
extract: -> body {body['items'].first}
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
##
|
|
59
|
+
# Return the path to execute the DailyMotion API request again.
|
|
60
|
+
# Channels and videos have different paths, so it depends on the type
|
|
61
|
+
#
|
|
62
|
+
# @return [String] Path
|
|
63
|
+
def info_path
|
|
64
|
+
@info_path ||= case @url
|
|
65
|
+
when regex?(:video_id) then "videos?id=#{$1}"
|
|
66
|
+
when regex?(:video_short_id) then "videos?id=#{$1}"
|
|
67
|
+
when regex?(:channel_id) then "channels?id=#{$1}"
|
|
68
|
+
when regex?(:channel_username) then "channels?forUsername=#{$1}"
|
|
69
|
+
when regex?(:channel_name) then "channels?forUsername=#{$1}"
|
|
70
|
+
else raise RequestError, "Invalid DailyMotion URL: #{@url}"
|
|
71
|
+
end + "&part=id,snippet&key=#{server_key}"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Parses a URL to find the type and identifier of a DailyMotion resource
|
|
75
|
+
def regex?(key)
|
|
76
|
+
host, name = '^(?:https?://)?(?:www\.)?', '([a-zA-Z0-9_-]+)'
|
|
77
|
+
case key
|
|
78
|
+
when :video_id then %r{#{host}dailymotion\.com/watch\?v=#{name}}
|
|
79
|
+
when :video_short_id then %r{#{host}youtu\.be/#{name}}
|
|
80
|
+
when :channel_id then %r{#{host}dailymotion\.com/channel/#{name}}
|
|
81
|
+
when :channel_username then %r{#{host}dailymotion\.com/user/#{name}}
|
|
82
|
+
when :channel_name then %r{#{host}dailymotion\.com/#{name}}
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: dm
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Claudio Baccigalupo
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2014-06-14 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: bundler
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.3'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '1.3'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rspec
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rake
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: yard
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: coveralls
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - ">="
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '0'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - ">="
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0'
|
|
83
|
+
description: DailyMotion + DailyMotion V3 API client.
|
|
84
|
+
email:
|
|
85
|
+
- claudio@fullscreen.net
|
|
86
|
+
executables: []
|
|
87
|
+
extensions: []
|
|
88
|
+
extra_rdoc_files: []
|
|
89
|
+
files:
|
|
90
|
+
- MIT-LICENSE
|
|
91
|
+
- README.md
|
|
92
|
+
- lib/dm.rb
|
|
93
|
+
- lib/dm/authenticable.rb
|
|
94
|
+
- lib/dm/client_tokens.rb
|
|
95
|
+
- lib/dm/google_account.rb
|
|
96
|
+
- lib/dm/readable.rb
|
|
97
|
+
- lib/dm/requestable.rb
|
|
98
|
+
- lib/dm/server_tokens.rb
|
|
99
|
+
- lib/dm/version.rb
|
|
100
|
+
- lib/dm/youtube_account.rb
|
|
101
|
+
- lib/dm/youtube_resource.rb
|
|
102
|
+
homepage: https://github.com/claudiob/dm
|
|
103
|
+
licenses:
|
|
104
|
+
- MIT
|
|
105
|
+
metadata: {}
|
|
106
|
+
post_install_message:
|
|
107
|
+
rdoc_options: []
|
|
108
|
+
require_paths:
|
|
109
|
+
- lib
|
|
110
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
111
|
+
requirements:
|
|
112
|
+
- - ">="
|
|
113
|
+
- !ruby/object:Gem::Version
|
|
114
|
+
version: 1.9.2
|
|
115
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
116
|
+
requirements:
|
|
117
|
+
- - ">="
|
|
118
|
+
- !ruby/object:Gem::Version
|
|
119
|
+
version: 1.3.6
|
|
120
|
+
requirements: []
|
|
121
|
+
rubyforge_project:
|
|
122
|
+
rubygems_version: 2.2.2
|
|
123
|
+
signing_key:
|
|
124
|
+
specification_version: 4
|
|
125
|
+
summary: Dm lets you interact with many resources provided by DailyMotion API V3.
|
|
126
|
+
test_files: []
|
|
127
|
+
has_rdoc:
|