transmission-rpc-ruby-ext 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 +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
|