putio-rb 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/.travis.yml +9 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +78 -0
- data/Guardfile +6 -0
- data/LICENSE.md +20 -0
- data/README.md +97 -0
- data/Rakefile +23 -0
- data/lib/putio-rb.rb +22 -0
- data/lib/putio/client.rb +81 -0
- data/lib/putio/client/files.rb +107 -0
- data/lib/putio/client/transfers.rb +26 -0
- data/lib/putio/configurable.rb +44 -0
- data/lib/putio/connection.rb +68 -0
- data/lib/putio/defaults.rb +59 -0
- data/lib/putio/resource/file.rb +33 -0
- data/lib/putio/resource/transfer.rb +11 -0
- data/lib/putio/version.rb +3 -0
- data/putio.gemspec +22 -0
- data/spec/lib/putio/client/files_spec.rb +144 -0
- data/spec/lib/putio/client_spec.rb +67 -0
- data/spec/lib/putio/configurable_spec.rb +44 -0
- data/spec/lib/putio/connection_spec.rb +77 -0
- data/spec/lib/putio/defaults_spec.rb +37 -0
- data/spec/lib/putio/resource/file_spec.rb +36 -0
- data/spec/lib/putio_spec.rb +24 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/support/file.json +17 -0
- data/spec/support/files.json +64 -0
- data/spec/support/shared_examples/configurable_examples.rb +84 -0
- data/spec/support/transfers.json +145 -0
- metadata +100 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'putio/resource/transfer'
|
2
|
+
|
3
|
+
module Putio
|
4
|
+
|
5
|
+
class Client
|
6
|
+
|
7
|
+
module Transfers
|
8
|
+
# Get all the transfers
|
9
|
+
#
|
10
|
+
# @return [Array]
|
11
|
+
def list_transfers
|
12
|
+
resp = get '/transfers/list'
|
13
|
+
|
14
|
+
resp.body.fetch('transfers').inject([]) do |memo, data|
|
15
|
+
memo.push transfer_factory.call(data)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
alias :transfers :list_transfers
|
19
|
+
|
20
|
+
private
|
21
|
+
def transfer_factory
|
22
|
+
@transfer_factory ||= Putio::Resource::Transfer.public_method(:new)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Putio
|
2
|
+
|
3
|
+
# Configuration options for {Client}, defaulting to values
|
4
|
+
# in {Default}
|
5
|
+
module Configurable
|
6
|
+
|
7
|
+
# @!attribute [w] access_token
|
8
|
+
# @see https://put.io/v2/docs/gettingstarted.html#authentication-and-access
|
9
|
+
# @return [String] OAuth2 access token for authentication
|
10
|
+
# @!attribute api_endpoint
|
11
|
+
# @return [URI] Base URL for API requests. default: https://api.put.io/
|
12
|
+
# @!attribute api_version
|
13
|
+
# @return [String] API version to use. default: v2
|
14
|
+
# @!attribute user_agent
|
15
|
+
# @return [String] User agent for http requests. default: 'putio-rb ruby client'
|
16
|
+
# @!attribute default_headers
|
17
|
+
# @return [Hash] Headers to use in http requests.
|
18
|
+
attr_accessor :access_token, :api_endpoint, :api_version, :user_agent, :default_headers
|
19
|
+
|
20
|
+
# List of configurable keys for {Putio::Client}
|
21
|
+
# @return [Array] of option keys
|
22
|
+
def self.keys
|
23
|
+
@keys ||= %i{ access_token api_endpoint api_version user_agent default_headers }
|
24
|
+
end
|
25
|
+
|
26
|
+
# Configure options with a block
|
27
|
+
def configure
|
28
|
+
yield self
|
29
|
+
end
|
30
|
+
|
31
|
+
# Reset configuration options to default values
|
32
|
+
def reset!
|
33
|
+
Putio::Configurable.keys.each do |key|
|
34
|
+
public_send("#{key}=".to_sym, Putio::Defaults.options[key])
|
35
|
+
end
|
36
|
+
self
|
37
|
+
end
|
38
|
+
alias setup reset!
|
39
|
+
|
40
|
+
def options
|
41
|
+
Hash[Putio::Configurable.keys.map { |key| [key, public_send(key.to_sym)] }]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'uri'
|
3
|
+
require 'net/http'
|
4
|
+
|
5
|
+
module Putio
|
6
|
+
|
7
|
+
class Connection
|
8
|
+
VERB_MAP = {
|
9
|
+
get: Net::HTTP::Get,
|
10
|
+
post: Net::HTTP::Post,
|
11
|
+
put: Net::HTTP::Put,
|
12
|
+
delete: Net::HTTP::Delete
|
13
|
+
}
|
14
|
+
|
15
|
+
def initialize(endpoint:, headers:{})
|
16
|
+
@endpoint = URI.parse(endpoint)
|
17
|
+
@headers = headers
|
18
|
+
end
|
19
|
+
|
20
|
+
def request_json(method, path, params)
|
21
|
+
response = request(method, path, params)
|
22
|
+
|
23
|
+
case response.code.to_i
|
24
|
+
when 200 || 201
|
25
|
+
body = JSON.parse(response.body)
|
26
|
+
response_factory.call(code: response.code.to_i, body: body)
|
27
|
+
when (400..499)
|
28
|
+
fail 'bad request'
|
29
|
+
when (500..599)
|
30
|
+
fail 'server problems'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def request(method, path, params)
|
35
|
+
case method
|
36
|
+
when :get
|
37
|
+
full_path = encode_path_params(path, params)
|
38
|
+
request = VERB_MAP[method].new(full_path)
|
39
|
+
else
|
40
|
+
request = VERB_MAP[method].new(path)
|
41
|
+
request.set_form_data(params)
|
42
|
+
end
|
43
|
+
|
44
|
+
http.request(request)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
attr_reader :endpoint
|
49
|
+
|
50
|
+
def http
|
51
|
+
@http ||= begin
|
52
|
+
http = Net::HTTP.new(endpoint.host, endpoint.port)
|
53
|
+
http.use_ssl = endpoint.scheme == 'https'
|
54
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
55
|
+
http
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def encode_path_params(path, params)
|
60
|
+
encoded = URI.encode_www_form(params)
|
61
|
+
[path, encoded].join('?')
|
62
|
+
end
|
63
|
+
|
64
|
+
def response_factory
|
65
|
+
@response_factory ||= ->(*args) { OpenStruct.new(*args) }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module Putio
|
4
|
+
|
5
|
+
# Default configuration options for the client
|
6
|
+
module Defaults
|
7
|
+
|
8
|
+
# Default API endpoint
|
9
|
+
API_ENDPOINT = 'https://api.put.io'
|
10
|
+
|
11
|
+
# Default API version
|
12
|
+
API_VERSION = 'v2'
|
13
|
+
|
14
|
+
# Default User Agent
|
15
|
+
USER_AGENT = 'putio-rb ruby client'
|
16
|
+
|
17
|
+
class << self
|
18
|
+
# Configuration options
|
19
|
+
# @return [Hash]
|
20
|
+
def options
|
21
|
+
Hash[Putio::Configurable.keys.map { |k| [k, public_send(k)] }]
|
22
|
+
end
|
23
|
+
|
24
|
+
# Default access token from ENV
|
25
|
+
# @return [String]
|
26
|
+
def access_token
|
27
|
+
ENV['PUTIO_ACCESS_TOKEN']
|
28
|
+
end
|
29
|
+
|
30
|
+
# Default API endpoint from ENV or {API_ENDPOINT}
|
31
|
+
# @return [String]
|
32
|
+
def api_endpoint
|
33
|
+
ENV.fetch('API_ENDPOINT', API_ENDPOINT)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Default API version from ENV or {API_VERSION}
|
37
|
+
# @return [String]
|
38
|
+
def api_version
|
39
|
+
ENV.fetch('API_VERSION', API_VERSION)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Default User Agent from ENV or {USER_AGENT}
|
43
|
+
# @return [String]
|
44
|
+
def user_agent
|
45
|
+
ENV.fetch('USER_AGENT', USER_AGENT)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Default headers for our http requests
|
49
|
+
# @return [Hash]
|
50
|
+
def default_headers
|
51
|
+
{
|
52
|
+
'User-Agent' => "#{user_agent}",
|
53
|
+
'Accept' => 'application/json'
|
54
|
+
}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Putio
|
2
|
+
module Resource
|
3
|
+
class File
|
4
|
+
VALID_KEYS = %i{ id name content_type is_mp4_available opensubtitles_hash
|
5
|
+
icon created_at parent_id first_accessed_at size screenshot is_shared
|
6
|
+
crc32 }.freeze
|
7
|
+
|
8
|
+
attr_reader *VALID_KEYS
|
9
|
+
|
10
|
+
def initialize(params = {})
|
11
|
+
params.reject! { |k,_| VALID_KEYS.include?(k) }
|
12
|
+
params.map { |k,v| instance_variable_set("@#{k}", v) }
|
13
|
+
end
|
14
|
+
|
15
|
+
def directory?
|
16
|
+
content_type == 'application/x-directory'
|
17
|
+
end
|
18
|
+
|
19
|
+
def shared?
|
20
|
+
is_shared
|
21
|
+
end
|
22
|
+
|
23
|
+
def mp4_available?
|
24
|
+
is_mp4_available
|
25
|
+
end
|
26
|
+
|
27
|
+
def created_at
|
28
|
+
created_at = super
|
29
|
+
Time.parse(created_at) if created_at
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/putio.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'putio/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = 'putio-rb'
|
8
|
+
s.version = Putio::VERSION
|
9
|
+
s.date = '2014-08-07'
|
10
|
+
s.summary = 'A gem to access put.io api'
|
11
|
+
s.description = 'putio-rb is a wrapper around put.io api v2 written in ruby.'
|
12
|
+
s.authors = ['Thibault Gautriaud']
|
13
|
+
s.email = 'thibault.gautriaud@gmail.com'
|
14
|
+
s.homepage = 'https://github.com/hubb/putio.rb'
|
15
|
+
|
16
|
+
s.required_ruby_version = '>= 2.0'
|
17
|
+
s.require_paths = ['lib']
|
18
|
+
s.files = `git ls-files`.split($/)
|
19
|
+
s.test_files = `git ls-files -- spec/*`.split($/)
|
20
|
+
|
21
|
+
s.add_development_dependency 'bundler'
|
22
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Putio::Client Files behaviour' do
|
4
|
+
let(:files) { File.read('spec/support/files.json') }
|
5
|
+
subject(:client) { Putio::Client.new(access_token: 'foobar') }
|
6
|
+
|
7
|
+
it { expect(client).to respond_to(:list_files) }
|
8
|
+
it { expect(client).to respond_to(:files) }
|
9
|
+
|
10
|
+
describe 'files' do
|
11
|
+
before do
|
12
|
+
stub_request(:get, "https://api.put.io/v2/files/list?oauth_token=foobar&parent_id=0").
|
13
|
+
with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
|
14
|
+
to_return(:status => 200, :body => files, :headers => {})
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should return a collection of Putio::Resource::File' do
|
18
|
+
expect(client.list_files).to be_kind_of(Array)
|
19
|
+
expect(client.list_files.first).to be_kind_of(Putio::Resource::File)
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'when the response is empty' do
|
23
|
+
before do
|
24
|
+
stub_request(:get, "https://api.put.io/v2/files/list?oauth_token=foobar&parent_id=0").
|
25
|
+
with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
|
26
|
+
to_return(:status => 200, :body => "{\"files\":[]}", :headers => {})
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should return an empty collection' do
|
30
|
+
expect(client.list_files).to be_kind_of(Array)
|
31
|
+
expect(client.list_files).to be_empty
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe 'search' do
|
37
|
+
before do
|
38
|
+
stub_request(:get, "https://api.put.io/v2/files/search/foobar?oauth_token=foobar").
|
39
|
+
with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
|
40
|
+
to_return(:status => 200, :body => files, :headers => {})
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should return a collection of Putio::Resource::File' do
|
44
|
+
result = client.search(query: 'foobar')
|
45
|
+
|
46
|
+
expect(result).to be_kind_of(Array)
|
47
|
+
expect(result.first).to be_kind_of(Putio::Resource::File)
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'when the response is empty' do
|
51
|
+
before do
|
52
|
+
stub_request(:get, "https://api.put.io/v2/files/search/foobar?oauth_token=foobar").
|
53
|
+
with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
|
54
|
+
to_return(:status => 200, :body => "{\"files\":[]}", :headers => {})
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should return an empty collection' do
|
58
|
+
result = client.search(query: 'foobar')
|
59
|
+
|
60
|
+
expect(result).to be_kind_of(Array)
|
61
|
+
expect(result).to be_empty
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'without query' do
|
66
|
+
it { expect { client.search }.to raise_error }
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'with a page' do
|
70
|
+
it 'should query the right page' do
|
71
|
+
mock_request = stub_request(:get, "https://api.put.io/v2/files/search/foobar/page/2?oauth_token=foobar").
|
72
|
+
with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
|
73
|
+
to_return(:status => 200, :body => "{\"files\":[]}", :headers => {})
|
74
|
+
|
75
|
+
client.search(query: 'foobar', options: { page: 2 })
|
76
|
+
|
77
|
+
assert_requested(mock_request)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'with other search syntax option' do
|
82
|
+
it 'should query with the right options' do
|
83
|
+
mock_request = stub_request(:get, "https://api.put.io/v2/files/search/foobar?ext=mp4&from=me&oauth_token=foobar&time=thisweek&type=video").
|
84
|
+
with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
|
85
|
+
to_return(:status => 200, :body => "{\"files\":[]}", :headers => {})
|
86
|
+
|
87
|
+
client.search(query: 'foobar', options: { from: 'me', type: 'video', ext: 'mp4', time: 'thisweek' })
|
88
|
+
|
89
|
+
assert_requested(mock_request)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe 'file' do
|
95
|
+
let(:file) { File.read('spec/support/file.json') }
|
96
|
+
|
97
|
+
it 'should query the right endpoint' do
|
98
|
+
mock_request = stub_request(:get, "https://api.put.io/v2/files/123?oauth_token=foobar&parent_id=0").
|
99
|
+
with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
|
100
|
+
to_return(:status => 200, :body => "{\"file\":[]}", :headers => {})
|
101
|
+
|
102
|
+
client.file(id: 123)
|
103
|
+
|
104
|
+
assert_requested(mock_request)
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'should return a Putio::Resource::File' do
|
108
|
+
stub_request(:get, "https://api.put.io/v2/files/123?oauth_token=foobar&parent_id=0").
|
109
|
+
with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
|
110
|
+
to_return(:status => 200, :body => file, :headers => {})
|
111
|
+
|
112
|
+
expect(client.file(id: 123)).to be_kind_of(Putio::Resource::File)
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'with a parent_id option' do
|
116
|
+
it 'should query with the right option' do
|
117
|
+
mock_request = stub_request(:get, "https://api.put.io/v2/files/123?oauth_token=foobar&parent_id=1234").
|
118
|
+
with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
|
119
|
+
to_return(:status => 200, :body => "{\"file\":[]}", :headers => {})
|
120
|
+
|
121
|
+
client.file(id: 123, options: { parent_id: 1234 })
|
122
|
+
|
123
|
+
assert_requested(mock_request)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe 'delete_files' do
|
129
|
+
before do
|
130
|
+
@mock_request = stub_request(:post, "https://api.put.io/v2/files/delete").
|
131
|
+
with(:body => {"file_ids"=>"1,2,3", "oauth_token"=>"foobar"},
|
132
|
+
:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type'=>'application/x-www-form-urlencoded', 'User-Agent'=>'Ruby'}).
|
133
|
+
to_return(:status => 200, :body => "{\"status\": \"OK\"}", :headers => {})
|
134
|
+
end
|
135
|
+
|
136
|
+
it { expect(client.delete_files(1,2,3)).to be_truthy }
|
137
|
+
|
138
|
+
it 'should query the right endpoint with options' do
|
139
|
+
client.delete_files(1,2,3)
|
140
|
+
|
141
|
+
assert_requested(@mock_request)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'putio/client'
|
3
|
+
|
4
|
+
describe Putio::Client do
|
5
|
+
let(:access_token) { 'foobar' }
|
6
|
+
subject(:client) { described_class.new(access_token: access_token) }
|
7
|
+
|
8
|
+
it_behaves_like 'a configurable'
|
9
|
+
|
10
|
+
# TODO: extract to files shared examples
|
11
|
+
it { expect(client).to respond_to(:list_files) }
|
12
|
+
# TODO: extract to transfers shared examples
|
13
|
+
it { expect(client).to respond_to(:list_transfers) }
|
14
|
+
|
15
|
+
describe 'inspect' do
|
16
|
+
it { expect(client.inspect).to be_kind_of(String) }
|
17
|
+
|
18
|
+
it 'should hide the access token' do
|
19
|
+
expect(client.inspect).not_to include(access_token)
|
20
|
+
expect(client.inspect).to include('*******')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it { expect(subject).to respond_to(:get) }
|
25
|
+
it { expect(subject).to respond_to(:post) }
|
26
|
+
it { expect(subject).to respond_to(:put) }
|
27
|
+
it { expect(subject).to respond_to(:delete) }
|
28
|
+
|
29
|
+
describe 'request' do
|
30
|
+
let(:connection) { double }
|
31
|
+
before do
|
32
|
+
allow(connection).to receive(:request_json).and_return(true)
|
33
|
+
client.connection = connection
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should add the access_token to the params' do
|
37
|
+
expect(connection).to receive(:request_json).with(anything, anything, hash_including(:oauth_token))
|
38
|
+
client.get('/foo/bar')
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should prepend the path with the api version' do
|
42
|
+
expect(connection).to receive(:request_json).with(anything, '/v2/foo/bar', anything)
|
43
|
+
client.get('/foo/bar')
|
44
|
+
end
|
45
|
+
|
46
|
+
%i{ get post put delete }.each do |method|
|
47
|
+
context "when the method is #{method.upcase}" do
|
48
|
+
it "should make a #{method.upcase} request" do
|
49
|
+
expect(connection).to receive(:request_json).with(method, anything, anything)
|
50
|
+
client.public_send(method, '/foo/bar')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe 'connection' do
|
57
|
+
let(:connection) { double(request_json: true) }
|
58
|
+
|
59
|
+
it 'should be initialised with the client endpoint and default_headers' do
|
60
|
+
expect(Putio::Connection).to receive(:new)
|
61
|
+
.with(endpoint: client.api_endpoint, headers: client.default_headers)
|
62
|
+
.and_return(connection)
|
63
|
+
|
64
|
+
client.get('/foo/bar')
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|