putio-rb 0.0.2
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/.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
|