transmission-rpc-ruby-ext 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +62 -0
- data/LICENSE +19 -0
- data/README.md +173 -0
- data/Rakefile +5 -0
- data/lib/transmission.rb +11 -0
- data/lib/transmission/arguments.rb +50 -0
- data/lib/transmission/arguments/location_set.rb +11 -0
- data/lib/transmission/arguments/session_set.rb +56 -0
- data/lib/transmission/arguments/torrent_add.rb +24 -0
- data/lib/transmission/arguments/torrent_set.rb +32 -0
- data/lib/transmission/config.rb +18 -0
- data/lib/transmission/extensions.rb +4 -0
- data/lib/transmission/extensions/torrent_actions.rb +15 -0
- data/lib/transmission/extensions/torrent_attributes.rb +103 -0
- data/lib/transmission/extensions/torrent_status.rb +42 -0
- data/lib/transmission/extensions/transmission.rb +82 -0
- data/lib/transmission/fields.rb +41 -0
- data/lib/transmission/fields/session_get.rb +61 -0
- data/lib/transmission/fields/session_stats.rb +15 -0
- data/lib/transmission/fields/torrent_get.rb +76 -0
- data/lib/transmission/model.rb +8 -0
- data/lib/transmission/model/session.rb +48 -0
- data/lib/transmission/model/session_stats.rb +28 -0
- data/lib/transmission/model/torrent.rb +152 -0
- data/lib/transmission/rpc.rb +116 -0
- data/lib/transmission/rpc/connector.rb +67 -0
- data/lib/transmission/utils.rb +24 -0
- data/spec/helpers/stubs.rb +82 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/transmission/arguments_spec.rb +78 -0
- data/spec/transmission/fields_spec.rb +60 -0
- data/spec/transmission/model/session_spec.rb +85 -0
- data/spec/transmission/model/torrent_spec.rb +345 -0
- data/spec/transmission/rpc/connector_spec.rb +82 -0
- data/spec/transmission/rpc_spec.rb +33 -0
- data/spec/transmission/utils_spec.rb +69 -0
- data/transmission-rpc-ruby-ext.gemspec +17 -0
- metadata +141 -0
@@ -0,0 +1,24 @@
|
|
1
|
+
module Transmission
|
2
|
+
class Arguments
|
3
|
+
class TorrentAdd < Transmission::Arguments
|
4
|
+
ATTRIBUTES = [
|
5
|
+
{ field: 'cookies' },
|
6
|
+
{ field: 'download-dir' },
|
7
|
+
{ field: 'filename' },
|
8
|
+
{ field: 'metainfo' },
|
9
|
+
{ field: 'paused' },
|
10
|
+
{ field: 'peer-limit' },
|
11
|
+
{ field: 'bandwidthPriority' },
|
12
|
+
{ field: 'files-wanted' },
|
13
|
+
{ field: 'files-unwanted' },
|
14
|
+
{ field: 'priority-high' },
|
15
|
+
{ field: 'priority-low' },
|
16
|
+
{ field: 'priority-normal' }
|
17
|
+
].freeze
|
18
|
+
|
19
|
+
REQUIRED = [
|
20
|
+
'filename metainfo'
|
21
|
+
].freeze
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Transmission
|
2
|
+
class Arguments
|
3
|
+
class TorrentSet < Transmission::Arguments
|
4
|
+
ATTRIBUTES = [
|
5
|
+
{ field: 'bandwidthPriority' },
|
6
|
+
{ field: 'downloadLimit' },
|
7
|
+
{ field: 'downloadLimited' },
|
8
|
+
{ field: 'downloadLimit' },
|
9
|
+
{ field: 'files-wanted' },
|
10
|
+
{ field: 'files-unwanted' },
|
11
|
+
{ field: 'honorsSessionLimits' },
|
12
|
+
{ field: 'ids' },
|
13
|
+
{ field: 'location' },
|
14
|
+
{ field: 'peer-limit' },
|
15
|
+
{ field: 'priority-high' },
|
16
|
+
{ field: 'priority-low' },
|
17
|
+
{ field: 'priority-normal' },
|
18
|
+
{ field: 'queuePosition' },
|
19
|
+
{ field: 'seedIdleLimit' },
|
20
|
+
{ field: 'seedIdleMode' },
|
21
|
+
{ field: 'seedRatioLimit' },
|
22
|
+
{ field: 'seedRatioMode' },
|
23
|
+
{ field: 'trackerAdd' },
|
24
|
+
{ field: 'trackerRemove' },
|
25
|
+
{ field: 'trackerReplace' },
|
26
|
+
{ field: 'uploadLimit' },
|
27
|
+
{ field: 'uploadLimited' },
|
28
|
+
{ field: 'uploadLimit' }
|
29
|
+
].freeze
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Transmission
|
2
|
+
class Config
|
3
|
+
class << self
|
4
|
+
def set(options = {})
|
5
|
+
@@config = options
|
6
|
+
@@connector = Transmission::RPC.new @@config
|
7
|
+
end
|
8
|
+
|
9
|
+
def get
|
10
|
+
@@config
|
11
|
+
end
|
12
|
+
|
13
|
+
def get_connector
|
14
|
+
@@connector
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module Transmission
|
2
|
+
module Model
|
3
|
+
class Torrent
|
4
|
+
# torrent attributes methods
|
5
|
+
def name
|
6
|
+
attributes['name']
|
7
|
+
end
|
8
|
+
|
9
|
+
def path
|
10
|
+
dir = File.expand_path(attributes['downloadDir'])
|
11
|
+
File.join(dir, name)
|
12
|
+
end
|
13
|
+
|
14
|
+
def id
|
15
|
+
attributes['id']
|
16
|
+
end
|
17
|
+
|
18
|
+
def hash
|
19
|
+
attributes['hashString']
|
20
|
+
end
|
21
|
+
|
22
|
+
def length
|
23
|
+
attributes['totalSize']
|
24
|
+
end
|
25
|
+
|
26
|
+
def valid
|
27
|
+
attributes['haveValid']
|
28
|
+
end
|
29
|
+
|
30
|
+
def percent_downloaded
|
31
|
+
(attributes['haveValid'] * 1.0 / attributes['totalSize']).round(2)
|
32
|
+
end
|
33
|
+
|
34
|
+
def percent_uploaded
|
35
|
+
(attributes['uploadedEver'] * 1.0 / attributes['totalSize']).round(2)
|
36
|
+
end
|
37
|
+
|
38
|
+
def percent_ratio
|
39
|
+
session = Transmission::Model::Session.get
|
40
|
+
return unless session.seed_ratio_limited
|
41
|
+
(attributes['uploadRatio'] * 1.0 / session.seed_ratio_limit).round(2)
|
42
|
+
end
|
43
|
+
|
44
|
+
def speed_download
|
45
|
+
attributes['rateDownload']
|
46
|
+
end
|
47
|
+
|
48
|
+
def speed_upload
|
49
|
+
attributes['rateUpload']
|
50
|
+
end
|
51
|
+
|
52
|
+
def ratio
|
53
|
+
(attributes['uploadRatio'] * 1.0).round(2)
|
54
|
+
end
|
55
|
+
|
56
|
+
def eta
|
57
|
+
pretty_time(attributes['eta']) if attributes['eta'] > 0
|
58
|
+
end
|
59
|
+
|
60
|
+
def file?
|
61
|
+
name = attributes['name']
|
62
|
+
files = attributes['files']
|
63
|
+
files.size == 1 && files.first['name'] == name
|
64
|
+
end
|
65
|
+
|
66
|
+
def folder?
|
67
|
+
!file?
|
68
|
+
end
|
69
|
+
|
70
|
+
def files
|
71
|
+
dir = File.absolute_path(attributes['downloadDir'])
|
72
|
+
attributes['files'].map { |f| File.join(dir, f['name']) }
|
73
|
+
end
|
74
|
+
|
75
|
+
def content
|
76
|
+
files.map { |f| File.basename(f) }
|
77
|
+
end
|
78
|
+
|
79
|
+
def biggest
|
80
|
+
b = attributes['files'].max_by { |f| f['length'] }
|
81
|
+
[File.basename(b['name']), b['length']]
|
82
|
+
end
|
83
|
+
|
84
|
+
def smallest
|
85
|
+
b = attributes['files'].min_by { |f| f['length'] }
|
86
|
+
[File.basename(b['name']), b['length']]
|
87
|
+
end
|
88
|
+
|
89
|
+
def magnet
|
90
|
+
attributes['magnetLink']
|
91
|
+
end
|
92
|
+
|
93
|
+
def trackers
|
94
|
+
url_regex = /([-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b)(?:[-a-zA-Z0-9@:%_\+.~#?&\/=]*)/i
|
95
|
+
attributes['trackers'].map do |r|
|
96
|
+
if (a = r['announce'].match(url_regex))
|
97
|
+
a[1]
|
98
|
+
end
|
99
|
+
end.compact
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Transmission
|
2
|
+
module Model
|
3
|
+
class Torrent
|
4
|
+
# torrent status methods
|
5
|
+
def paused?
|
6
|
+
attributes['status'] == 0
|
7
|
+
end
|
8
|
+
|
9
|
+
def queued?
|
10
|
+
attributes['status'] == 3
|
11
|
+
end
|
12
|
+
|
13
|
+
def downloading?
|
14
|
+
attributes['status'] == 4
|
15
|
+
end
|
16
|
+
|
17
|
+
def seeding?
|
18
|
+
attributes['status'] == 6
|
19
|
+
end
|
20
|
+
|
21
|
+
def isolated?
|
22
|
+
attributes['status'] == 7
|
23
|
+
end
|
24
|
+
|
25
|
+
def finished?
|
26
|
+
attributes['isFinished']
|
27
|
+
end
|
28
|
+
|
29
|
+
def completed?
|
30
|
+
attributes['percentDone'] >= 1
|
31
|
+
end
|
32
|
+
|
33
|
+
def incomplete?
|
34
|
+
attributes['percentDone'] < 1
|
35
|
+
end
|
36
|
+
|
37
|
+
def error?
|
38
|
+
attributes['error'] != 0
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Transmission
|
2
|
+
# list torrents methods
|
3
|
+
def self.all(connector = nil)
|
4
|
+
t = Transmission::Model::Torrent.all connector: connector
|
5
|
+
case t.ids.size
|
6
|
+
when 0 then Array([])
|
7
|
+
when 1 then Array(t)
|
8
|
+
else Array(t.torrents)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.finished
|
13
|
+
all.select { |t| t.attributes['isFinished'] }
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.completed
|
17
|
+
all.select { |t| t.attributes['percentDone'] >= 1 }
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.incomplete
|
21
|
+
all.select { |t| t.attributes['percentDone'] < 1 }
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.paused
|
25
|
+
all.select { |t| t.attributes['status'] == 0 }
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.queued
|
29
|
+
all.select { |t| t.attributes['status'] == 3 }
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.downloading
|
33
|
+
all.select { |t| t.attributes['status'] == 4 }
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.seeding
|
37
|
+
all.select { |t| t.attributes['status'] == 6 }
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.error
|
41
|
+
all.select { |t| t.attributes['error'] != 0 }
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.hashes
|
45
|
+
all.map { |t| t.attributes['hashString'] }
|
46
|
+
end
|
47
|
+
|
48
|
+
# find torrents methods
|
49
|
+
def self.find_by_name(name)
|
50
|
+
re = name.split(' ').join('.*')
|
51
|
+
all.select { |t| t.attributes['name'] =~ /#{re}/i }
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.find_by_hash(hash)
|
55
|
+
all.select { |t| t.attributes['hashString'].casecmp(hash) == 0 }
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.find_by_id(id)
|
59
|
+
all.select { |t| t.attributes['id'] == id }
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.find_by_tracker(tracker)
|
63
|
+
url_regex = /([-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b)(?:[-a-zA-Z0-9@:%_\+.~#?&\/=]*)/i
|
64
|
+
re = tracker.split(' ').join('.*')
|
65
|
+
all.select do |t|
|
66
|
+
trackers = t.attributes['trackers'].map do |r|
|
67
|
+
if (a = r['announce'].match(url_regex))
|
68
|
+
a[1]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
trackers.any? { |r| r =~ /#{re}/i }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# add torrents methods
|
76
|
+
def self.add(file, connector = nil)
|
77
|
+
Transmission::Model::Torrent.add(
|
78
|
+
connector: connector,
|
79
|
+
arguments: { filename: file }
|
80
|
+
)
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require_relative 'fields/torrent_get'
|
2
|
+
require_relative 'fields/session_get'
|
3
|
+
require_relative 'fields/session_stats'
|
4
|
+
require_relative 'utils'
|
5
|
+
|
6
|
+
module Transmission
|
7
|
+
class Fields
|
8
|
+
class InvalidField < StandardError; end
|
9
|
+
|
10
|
+
attr_accessor :fields
|
11
|
+
|
12
|
+
ATTRIBUTES = []
|
13
|
+
|
14
|
+
def initialize(fields = nil)
|
15
|
+
@fields = fields.inject([]) do |fields, field|
|
16
|
+
found = self.class::ATTRIBUTES.select { |attr| attr[:field] == field }
|
17
|
+
raise Transmission::Fields::InvalidField, field if found.empty?
|
18
|
+
fields << field
|
19
|
+
end if fields
|
20
|
+
@fields = self.class::ATTRIBUTES.collect do |key|
|
21
|
+
key[:field]
|
22
|
+
end if fields.nil?
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_fields
|
26
|
+
@fields
|
27
|
+
end
|
28
|
+
|
29
|
+
class << self
|
30
|
+
include Transmission::Utils
|
31
|
+
|
32
|
+
def is_valid?(key)
|
33
|
+
is_valid_key? key, self::ATTRIBUTES
|
34
|
+
end
|
35
|
+
|
36
|
+
def real_key(key)
|
37
|
+
option_key key, self::ATTRIBUTES
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Transmission
|
2
|
+
class Fields
|
3
|
+
class SessionGet < Transmission::Fields
|
4
|
+
ATTRIBUTES = [
|
5
|
+
{ field: 'alt-speed-down' },
|
6
|
+
{ field: 'alt-speed-enabled' },
|
7
|
+
{ field: 'alt-speed-time-begin' },
|
8
|
+
{ field: 'alt-speed-time-enabled' },
|
9
|
+
{ field: 'alt-speed-time-end' },
|
10
|
+
{ field: 'alt-speed-time-day' },
|
11
|
+
{ field: 'alt-speed-up' },
|
12
|
+
{ field: 'blocklist-url' },
|
13
|
+
{ field: 'blocklist-update' },
|
14
|
+
{ field: 'blocklist-enabled' },
|
15
|
+
{ field: 'blocklist-size' },
|
16
|
+
{ field: 'cache-size-mb' },
|
17
|
+
{ field: 'config-dir' },
|
18
|
+
{ field: 'download-dir' },
|
19
|
+
{ field: 'download-queue-size' },
|
20
|
+
{ field: 'download-queue-enabled' },
|
21
|
+
{ field: 'dht-enabled' },
|
22
|
+
{ field: 'encryption' },
|
23
|
+
{ field: 'required' },
|
24
|
+
{ field: 'preferred' },
|
25
|
+
{ field: 'tolerated' },
|
26
|
+
{ field: 'idle-seeding-limit' },
|
27
|
+
{ field: 'idle-seeding-limit-enabled' },
|
28
|
+
{ field: 'incomplete-dir' },
|
29
|
+
{ field: 'incomplete-dir-enabled' },
|
30
|
+
{ field: 'lpd-enabled' },
|
31
|
+
{ field: 'peer-limit-global' },
|
32
|
+
{ field: 'peer-limit-per-torrent' },
|
33
|
+
{ field: 'pex-enabled' },
|
34
|
+
{ field: 'peer-port' },
|
35
|
+
{ field: 'peer-port-random-on-start' },
|
36
|
+
{ field: 'port-forwarding-enabled' },
|
37
|
+
{ field: 'queue-stalled-enabled' },
|
38
|
+
{ field: 'queue-stalled-minutes' },
|
39
|
+
{ field: 'rename-partial-files' },
|
40
|
+
{ field: 'rpc-version' },
|
41
|
+
{ field: 'rpc-version-minimum' },
|
42
|
+
{ field: 'script-torrent-done-filename' },
|
43
|
+
{ field: 'script-torrent-done-enabled' },
|
44
|
+
{ field: 'done' },
|
45
|
+
{ field: 'seedRatioLimit' },
|
46
|
+
{ field: 'seedRatioLimited' },
|
47
|
+
{ field: 'seed-queue-size' },
|
48
|
+
{ field: 'seed-queue-enabled' },
|
49
|
+
{ field: 'speed-limit-down' },
|
50
|
+
{ field: 'speed-limit-down-enabled' },
|
51
|
+
{ field: 'speed-limit-up' },
|
52
|
+
{ field: 'speed-limit-up-enabled' },
|
53
|
+
{ field: 'start-added-torrents' },
|
54
|
+
{ field: 'trash-original-torrent-files' },
|
55
|
+
{ field: 'units' },
|
56
|
+
{ field: 'utp-enabled' },
|
57
|
+
{ field: 'version' }
|
58
|
+
].freeze
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Transmission
|
2
|
+
class Fields
|
3
|
+
class SessionStats < Transmission::Fields
|
4
|
+
ATTRIBUTES = [
|
5
|
+
{ field: 'activeTorrentCount' },
|
6
|
+
{ field: 'downloadSpeed' },
|
7
|
+
{ field: 'pausedTorrentCount' },
|
8
|
+
{ field: 'torrentCount' },
|
9
|
+
{ field: 'uploadSpeed' },
|
10
|
+
{ field: 'cumulative-stats' },
|
11
|
+
{ field: 'current-stats' }
|
12
|
+
].freeze
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|